Chromium Web Browser Logo

Chromium extension tutorial

Por supuesto que no estamos hablando del elemento químico cromo (“chromium” en inglés) sino del popular navegador web de código abierto para todos. Lo que desarrollaremos es una “extensión”, una herramienta integrada al navegador y que tiene muy diferentes propósitos. Con fines didácticos haremos una extensión muy sencilla que nos redirige hacia una página web que nos devuelve simplemente nuestra propia dirección IPv4, ¡manos al teclado!

¿Qué es una extensión para Chromium?

Chromium Web Browser Logo

Como ya lo definimos al principio, una herramienta puede tener fines diversos, uno o más:

  • Pueden ser usadas para notificarnos si tenemos nuevos mensajes de correo electrónico por medio del pequeño icono que se coloca al lado de la barra de direcciones.
  • Si no hemos iniciado sesión en nuestra cuenta de correo-e basado en web, podemos hacer click en el icono para ir a la página donde introduciremos nuestras credenciales (¡Cuidado con las páginas falsas o “phishing”!).
  • Podría alertarnos si una palabra clave en particular aparece en la página que estemos visitando.
  • Podríamos programarla para NO cargar las imágenes de un sitio determinado -o todos los que visitemos-.
  • Tal vez sería útil para alertarnos de la modificación de una página (aunque para ellos hay lectores RSS específicos para ese trabajo) o su cambio de estado.
  • ¡Incluso, si somos aventureros, nos permitiría programar una calculadora!

Como ven los usos son muchos y variados, nuestra imaginación no tiene límites más sin embargo el entorno donde va a funcionar nuestra novel extensión sí que está supeditada al navegador Chromium. Esencialmente una extensión es una pequeñita página web que está alojada en un navegador web – en este caso Chromium – y que además puede acceder a ciertas funciones API (“Application Programming Interface“: conjunto de clases, métodos y funciones normalizadas).

La que nosotros vamos a realizar es bastante modesta y a medida que avanzemos la iremos profundizando más, pero la idea es introduciros en esta área de programación en un entorno de desarrollo bastante peculiar.

Creando el proyecto.

Pues que para comenzar crearemos en nuestro disco duro, donde gustemos, una carpeta con el nombre “KS7000_ConoceTuIPv4” – o el nombre que vosotros querais, sed de libre albedrío, lo importante es que aprendamos los conceptos y procedimientos-.

Primer componente de nuestra extensión en Chromium.

Como somos inclinados al dibujo técnico más que al dibujo artístico (¡Ea, que por allí viene nuestro tutorial sobre Inkscape!) lo que hicimos fue redimensionar un logotipo en formato PNG (que ya teníamos rodando por internet) a un tamaño de 16 por 16 píxeles ya que necesitados una pequeña interfaz gráfica para el botón donde nuestros usuarios harán click y abrirán nuestro trabajo. Cuando “subamos” – y especifiquemos- este icono a Chromium no tendremos que programar línea alguna: ya el navegador sabrá qué hacer al evento de hacer click sobre nuestra pequeña obra de arte microscópica (935 bytes “pesa” el fichero):

KS7000_ConoceTuIPv4 (icono)

Precisamente queremos hacer hincapié en este punto: esa imagen pequeñita que vamos a especificar ya Chromium le añade el evento click para cargar y ejecutar los siguientes componentes que vamos a crear, eso es, en sí, una Interfaz de Programación de Aplicaciones “API” -normalizadas en un ambiente determinado (Chromium, en este caso) -.

Creando un archivo de manifiesto.

Un manifiesto es simplemente una declaración de propósitos o programas. Para este caso es un fichero llamado manifest.json y por su extensión deducireis que está en lenguaje JSON: JavaScript Object Notation, el cual permite el intercambio de información entre cliente y servidor. Aunque está basado en la norma ECMA-262 3ª edición de 1999 nosotros consideramos que es una norma de facto. En todo caso no representa mayor misterio, tal como lo es XML, el JSON (a menos que guarde datos binarios) es plenamente legible tanto a humanos como a máquinas, pasemos a analizar su estructura mínima necesaria:

{
  "manifest_version": 2,
  "name": "KS7000_ConoceTuIPv4",
  "version": "1.0",
}

Explicado línea por línea, los tres primeros elementos son obligatorios:

  1. “manifest_version”: toma el valor 2 -sin comillas- para indicar que es a partir de la versión 18 de Chromium que funcionará la extensión. Al momento de escribir este reportaje vamos por la versión 59 así que ya sabeis que la versión 1 está obsoleta e inútil, de hecho. Notad cada coma para indicar separación de componentes, lo colocamos antes del fin de línea y retorno de carro.
  2. “name”: con hasta un máximo de 45 caracteres, es como identificaremos nuestra extensión y tratad que sea bien original y único si es que quereis algún día hacerlo famoso por internet y evitar malentendidos con otros programadores o incluso poderosas corporaciones.
  3. “version”: pues la numeración que utilizemos para identificar los cambios que le hagamos, y aunque está entrecomillado no os equivoquéis: son cuatro enteros de ntreo cero y 65535 separados por puntos y sirven para identificar – y actualizar a nuestros usuarios si hacemos una mejora -. En nuestro ejemplo colocamos “1.0” ¿Dónde diablos están los otros dos números faltantes? Pues en realidad nuestra versión es “1.0.0.0”, tened mucho cuidado al numerar porque como dijimos se usa para comparar y actualizar, de ser necesario, a nuestros usuarios.

Más adelante ahondaremos en otras propiedades que deberíamos agregar y que implican otros ficheros en nuestra mini aplicación, per antes de finalizar esta sección os contamos que hay otras propiedades interesantes:

  • “description”: la descripción de lo que realiza nuestra extensión, para lo que sirve, sed breve y conciso; entrecomillad.
  • “short_name“: que soporta hasta 12 caracteres y es especialmente útil para titular las pestañas y el lanzador de aplicaciones (en teoría).
  • “version_name”: un nombre no necesariamente numérica, si queremos colocarle un nombre afectuoso, deberiamos tratar de que sea único.

Así las cosas nuestro archivo de manifiesto va quedando como sigue:

{
  "manifest_version": 2,
  "name": "KS7000_ConoceTuIPv4",
  "short_name": "KS7000_IP",
  "description": "Esta extensión os permitirá saber vuestra dirección IPv4.",
  "version": "1.0",
  "version_name": "TuIPv4",
}

¿Acciones de página o acciones de navegador?

Aunque dijimos que Chromium sabría qué hacer con nuestra extensión, esto no es totalmente cierto ya que en esta API desarrollaron dos aciones principales de la cual debemos especificar que nuestra extensión realize alguna de las dos (o ninguna: si es ninguna pues no obtenemos ningún resultado, es una extensión inútil).

  • Acción de navegador: se ejecutará en cualquier pestaña y paǵina que abramos y permite que nuestros usuarios interactuen con nuestra extensión (ejecutar una orden o cambiar las preferencias, por ejemplo).
  • Acción de página: es un icono que indica un estado o condición a la página que estamos visitando (¿recuerdan que propusimos, al principio, una extensión que buesque y notifique la existencia de una palabra clave? pues eso, se puede activar -o no- si esa palabra clave está presente). Esta acción NO permite interactuar con los usuarios, es más bien informativa.

Nosotros usaremos la acción de navegador para lo cual debemos escribir:

"browser_action": {}

y colocamos entre los corchetes los elementos que queremos especificar y que a continuación especificamos:

 "default_icon": "KS7000_ConoceTuIPv4.png",
 "default_popup": "aviso.html"

La primera línea indicamos que utilice el ícono que os mostramos al principo, pero !ah,caramba! ¿habiais dicho que Chromium sabrá que hacer por nosotros? pues aquí el detalle no es culpa de Chromium ya que debido a los múltiples dispositivos (hardware) que pueden ejecutar este navegador web son muy diversos, los tamaños de pantalla son muy diversos también así que debemos -en teoría- hacer íconos de diferentes tamaños Y CHROMIUM SE ENCARGARÁ DE MOSTRAR EL QUE SEA DEL TAMAÑO ADECUADO AL DISPOSITIVO y tal como prometimos nos “harán” el trabajo a nosotros los programadores.

Acá nos quedaremos con un solo ícono, queda para vosotros estudies cómo especificar más iconos. La segunda línea establece cuál archivo .html queremos mostrar cuando el usuario haga click, y de nuevo es cuestión de tener variedad de opciones ya que podemos hacer varios ficheros .html (según la complejidad de nuestra extensión) pero debemos decirle al navegador cual queremos que muestre primero, así solo sea una la que “subamos” ¡NO ESTAMOS PROGRAMANDO EN PYTHON, TAMPOCO ESPERÉIS MILAGROS!

Archivo de manifiesto, versión final, debidamente indentado.

{
  "manifest_version": 2,
  "name": "KS7000_ConoceTuIPv4",
  "short_name": "KS7000_IP",
  "description": "Esta extensión os permitirá saber vuestra dirección IPv4.",
  "version": "1.0",
  "version_name": "TuIPv4",

  "browser_action": {
    "default_icon": "KS7000_ConoceTuIPv4.png",
    "default_popup": "aviso.html"
  } 
}

Elemento emergente de interfaz.

Ya sabemos que nos falta ahora un elemento, el “default_popup” al cual le asignamos el nombre “aviso.html” y como este tema no es un tutorial de HTML5 pues de una os colocamos el código del fichero de marras:

<!doctype html system "about:legacy-compat">
<html lang="es-419">
  <head>
    <meta charset="UTF-8">
    <title>KS7000</title>
  </head>
  <body>
    <h1>KS7000_ConoceTuIPv4</h1>
    <a href="http://www.soporteweb.com/" target="_blank">Haz click para saber saber vuestra dirección IPv4</a>
  </body>
</html>

“Subiendo” nuestra extensión.

Pues tanto como “subir” no será, no vamos a publicar nada por internet (aún no, por lo menos). Para nuestro ejemplo estamos ejecutando Ubuntu 16 64 bits al cual le instalamos Chromium 59 y en la barra de direcciones escribimos lo siguiente:

chrome://extensions/

Luego presionamos Intro o Enter y veremos algo muy parecido a esto:

Chromium instalar y configurar extensiones
Chromium instalar y configurar extensiones

En letras verdes os indicamos dónde “clickar” para activar el modo de programador, se os habilitan tres botones pero el primero de izquierda a derecha es el que nos interesa, el que pone “CARGAR EXTENSIÓN SIN EMPAQUETAR” ya que le vamos simplemente a indicar la carpeta que a tal efecto creamos al comenzar este tutorial. Dice que es “sin empaquetar” porque para publicar nuestra extensión en internet debemos comprimirla en un formato específico y con una herramienta específica que no solamente ahorra tamaño sino que también agrega seguridad, pero no es tema de este tutorial, allí teneis los enlaces si quereis estudiarlos a fondo.

KS7000_ConoceTuIPv4 instalado en Chromium
KS7000_ConoceTuIPv4 instalado en Chromium

Así veremos cuando está instalada nuestra extensión, notad el icono al finalizar la barra de direcciones al cual al hacerle click nos muestra lo siguiente:

KS7000_ConoceTuIPv4 ventana emergente
KS7000_ConoceTuIPv4 ventana emergente

En esa ventana pequeñita es que se “ejecuta” nuestra página web con el enlace deseado, pues bueno, click y listo, se abre una pestaña nueva (ya que usamos el target “_blank”) y vamos a un dominio cuyo único trabajo es devolver la dirección pública IPv4 de nosotros los internautas. ¡Felicidades, hemos creado nuestra primera extensión!

Posibles problemas.

Seguimos insistiendo con las API‘s: si tenemos algún error en nuestro código, “una metida de pata”, el Chromium nos indicará y animará a seguir intentando; en este ejemplo a propósitos omitimos unas comillas de apertura, es decir, no la pusimos por pares y al cargar nos indica esto:

KS7000_ConoceTuIPv4 mensaje de error en comillas de apertura
KS7000_ConoceTuIPv4 mensaje de error en comillas de apertura

El mensaje indica que es un token desconocido, pues claro, no está bien delimitado el elemento y asume que queremos declarar un dichoso token: ¡todo esto por una simple comilla doble que omitimos!

Usando guiones JavaScript.

Recordemos que JavaScript lo podemos ubicar tanto dentro de un archivo html como en un archivo aparte js que sea llamado, desde luego, el fichero html. Ambos métodos son soportados por las extensiones en Chromium y vamos a revisar las dos opciones.

Guiones JavaScript internos.

Primero eliminamos la extensión que creamos en Chromium y vamos a agregar el siguiente guión JavaScript justo en la cabecera <head>:

 <script>alert("Aviso de JavaScript");</script>

A continuación reinstalamos desde nuestra consabida carpeta y hacemos click en el icono de la extensión instalada (si no os funciona, revisad de nuevo bien desde el principio de este artículo) y lograremos ver el siguiente aviso que os lo resaltamos en color verde:

KS7000_ConoceTuIPv4 JavaScript error
KS7000_ConoceTuIPv4 JavaScript error

Cuando hacemos click en diho botón veremos algo parecido a esto:

KS7000_ConoceTuIPv4 hash error
KS7000_ConoceTuIPv4 hash error

¿Qué ha sucedido aquí? Pues simple y llanamente que Chromium tiene ciertos requisitos de seguridad basados en recomendaciones de la W3C a fin de proteger la integridad de nuestro software. Para que se pueda ejecutar algún guión JavaScript insertado en un fichero HTML debemos calcular el hash (tenemos un tutorial que explica este tema) del fichero en cuestión en insertarlo en el manifiesto mediante un comando específico.

Para ello ya tenemos la mitad del trabajo hecho: el cálculo del hash lo hace Chromium sin siquiera pedirselo, así que lo aprovechamos para agregarlo en manifest.json y la idea es que al declararlo se obliga a compararlo con el generado al archivo HTML y si ambos coinciden se considera que no ha habido alteraciones a nuestro trabajo por parte de terceras personas con buenos o malos propósitos.

Debemos entonces incluir estas lineas en el manifiesto:

"content_security_policy": "default-src 'self' 'sha256-jLjrqnmi4O/pyY5/8e4eXAPbFQ6Vq8j76usKTBjmtb4='),

Recargamos con CTRL+R y repetimos el proceso, y ahora logramos ejecutar con éxito:

KS7000-ConoceTuIPv4 mensaje de JavaScript
KS7000-ConoceTuIPv4 mensaje de JavaScript

Para que tengamos presente la seguridad, si cambiamos un solo caracter de “aviso.html” inmediatamente Chromium dejará de ejecutar cualquier script que haya dentro del archivo. Para poder ejecutarlo de nuevo, debemos volver a actualizar el hash, pero surge la pregunta ¿y si el atacante también modifica el hash dentro del manifiesto? Si estamos en nuesstros propios ordenadores pues esto es más que dificil que suceda, un atacante no va a invertir tiempo y esfuerzo para malograr un solo ordenador, es lógico que busque atacar cientos o miles de computadoras así que el obejtivo sería un repositorio en internet y allí interviene lo que comentamos: para “subir” nuestra aplicación para se repartido por internet no solamente la debemos comprimir, SINO QUE TAMBIÉN LE TENEMOS QUE AGREGAR UN HASH AL ARCHIVO COMPRIMIDO (recordad la herramienta crxmake).

Para comprobar lo que afirmamos, solo basta modificar un solo caracter en el fichero aviso.html, nosotros le agregamos par de símbolos de admiración en el mensaje y aunque no afecte para absolutamente nada la seguridad de nuestro equipo de igual manera se muestra la línea que ha sido modificada (o, en la vida real “hackeada”), mirad:

KS7000_ConoceTuIPv4 modificado y el hash es distinto del registrado
KS7000_ConoceTuIPv4 modificado y el hash es distinto del registrado

Como nota curiosa, ya logramos que el guión se ejecute pero eso es solo lo que hará Chromium, es decir, el archivo aviso.html no será mostrado pero poco importa para nosotros porque simplemente estamos aprendiendo a programar, por ello nos olvidaremos de incluir una instrucción de este tipo que llamamos modal. Una ventana modal es aquella que se posesiona del enfoque de una aplicación y la única manera de continuar es obedecer la instrucción que ordena. Para que aprendamos los guiones que se guardan en un fichero aparte, externo a un fichero html, debemos presentar los conceptos de ejecuciones síncronas y asíncronas.

Guiones síncronos y asíncronos.

La principal diferencia entre ambos métodos estriba que mientras el método síncrono detiene su ejecución y espera el resultado o liberación de recursos, el proceso asíncrono se ejecuta por sí solo y va de manera independiente (interactue o no con el proceso que le dio origen). Se pudiera decir que ambos procesos “padre” e “hijo” deberían de alguna forma comunicarse y esto se debe hacer por medio del entorno de desarrollo o IDE, por sus iniciales en inglés de “Integrated Development Environment” o Ambiente de Desarrollo integrado, lo cual simplifica enormemente nuestro trabajo de programación ya que nos permite abstraernos en programar solamente sin importar el hardware o sistema operativo utilizado (si se quiere lo podríamos ver como “aislado por capas” como lo es el modelo OSIpara las redes de ordenadores).

Generando un proceso asíncrono.

Vamos entonces a modificar nuestro fichero “aviso.html” de la siguiente manera, resaltado en verde los cambios:

<!doctype html system "about:legacy-compat">
<html lang="es-419">
  <head>
    <meta charset="UTF-8">
    <title>KS7000</title>
  </head>
  <body>
    <h1>KS7000_ConoceTuIPv4</h1>
    <button id="conoceIPv4">¡Conoce tu dirección IPv4!</button>
    <p id="IPv4"></p>
    <script src="emergente.js"></script>  </body>
</html>

¡ IMPORTANTE ! : declarad vuestro guion externo en JavaScript DESPUÉS de los elementos, de lo contrario arrojará un error “null” indicando que los elementos no existen. Esto es así debido a que el analizador “parser” va de arriba hacia abajo, línea por línea, y el proceso asíncrono que lanzamos debe tener con qué trabajar. En este caso hay dos elementos que “pasaremos”: el botón identificado como “conoceIPv4” y el párrafo sin texto o “en blanco” identificado como”IPv4″.

Ahora vamos a crear nuestro elemento escrito en JavaScript. un guión que, por ahora, simplemente colocará un mensajito de texto en el párrafo identificado como “IPv4”:

document.getElementById("conoceIPv4").addEventListener("click", buscaIPv4);
  function buscaIPv4() {
    document.getElementById("IPv4").innerHTML = "vuestra IPv4 es:";
  }

Como veis es algo bien sencillo:

  • En la primera línea declaramos que al documento identificado como “conoceIPv4” le agregue un evento que esté en función de si el usuario hace click en el botón y que ejecute la función “buscaIPv4”.
  • A su vez la función buscaIPv4 POR AHORA lo único que hace es sustituir al elemento (párrafo) con el identificador “IPv4” y lo sustituya con el mensaje “Vuestra IPv4 es:”.

Al guardar y recargar con CTRL+R las extensiones instaladas va a volver a mostrarnos el mensaje de que los hash NO coinciden, copiamos el hash actualizado y lo pegamos en el fichero manifiest.json para volver a recargar y ejecutar, podréis observar algo muy parecido a esto:

KS7000_ConoceTuIPv4 mensaje de encabezado
KS7000_ConoceTuIPv4 mensaje de encabezado

¡LISTO, HEMOS CREADO UN PROCESO ASÍNCRONO! MUY FÁCIL, ¿CIERTO? 🤓

Creando

Comprobando compatibilidad en Mozilla Firefox.

Por medio de la cuenta Twitter de un desarrollador web de Mauritania tuvimos la excelente oportunidad de revisar cómo se desarrolla una extensión en Mozilla Firefox (versión 45 o superior) y además cómo preparse para presentarla al público, todo muy detallado y bien pensado.

Como Chromium y Firefox ambos comparten el entorno de programación chrome hace que compartan la misma estructura de datos pero se “llega” de diferente manera. Primero debemos introducir en la barra de direcciones el siguiente comando:

about:debugging

Presionamos la tecla intro y seleccionamos complementos y hacemos click en el botón “Cargar complementario temporario” (sí, suena extraño en castellano pero si queremos colaborar con las traducciones, pues las puertas están abiertas). Seleccionamos la carpeta con nuestro mini proyecto y listo ¡a comprobar!

KS7000_ConoceTuIPv4 ejecutado en Mozilla Firefox
KS7000_ConoceTuIPv4 ejecutado en Mozilla Firefox

Fuentes consultadas.

En idioma francés.

En idioma italiano.

En idioma inglés.

PHP Simple HTML DOM Parser

Para abrir el mes de junio seguimos el hilo en nuestros artículos que buscan difundir el conocimiento libre del Patrimonio Tecnológico de la Humanidad. En anterior oportunidad estudiamos PHP curl, una herramienta basada en cURL y por ende en libcurl (¡ea, esto último no lo mencionamos allá!). Como en ese caso obtuvimos un método para descargar páginas web enteras, incluso si hay que pasarle datos con el método POST y/o hay que introducir usuario y contraseña. Esta entrada busca extraer, analizar e incluso modificar dichos datos ¡vente con nosotros!

PHP Simple HTML DOM Parser.

Presentación.

Buscábamos una “parser” o analizador código HTML y aunque PHP tiene su modelo establecido nos decantamos por algo más fácil pero con el inconveniente que debemos apoyar la licencia de uso del Instituto Tecnológico de Massachusetts (“MIT license”) y que NO viene integrado al lenguaje PHP. Lo bueno es que apenas son 65037 bytes en un archivo con un guion escrito en lenguaje PHP para que funcione (la licencia nos obliga a distribuir completo los archivos de ejemplos y manuales, todos escritos en idioma inglés).

El analizador de HTML (y XML) que veremos y aprenderemos a usar tiene el pomposo nombre de “PHP Simple HTML DOM Parsercon todas las implicaciones que derivan de llamar “simple” al D.O.M. (“Document Object Model”).

Document Object Model.

El Modelo de Objeto Documento es una norma propuesta por el Consorcio World Wide Web o W3C que son quienes hacen las recomendaciones y sientan las bases, de facto, del Web creado por el Doctor Tim Berners-Lee. En dicho papel de trabajo, a nuestro modo de ver las cosas, se propone que una página web es un documento y todo lo que está contenido en ella está representada por nodos. Si nos ponemos a ver tiene sentido porque la norma HTML5 establece unas sub divisiones que a su vez contienen títulos, sub títulos, párrafos, listas, etc.

Este concepto es mucho más amplio porque contempla, aparte de propiedades, también métodos que por definición HTML5 no contempla y para respetar la neutralidad hacen de la vista gorda del JavaScript (¿definirán algún día al CSS para suplantarlo? Sí, los sabemos, nuestro pensamiento siempre es profano).

El DOM está estructurado sobre tres pilares básicos:

  • “Core DOM”: modelo normativo para todos los tipos de documentos.
  • “XML DOM”: para documentos XML (febrero, 1998).
  • “HTML DOM”: no menos importante, aunque aparezca en tercer lugar, para documentos HTML.

Autores.

La idea original proviene de José Solorzano quien comenzó un proyecto bautizado como “HTML Parser for PHP 4” (dale con esto de los nombres largos ¿será que estoy leyendo muchos artículos en inglés y me estoy contagiando? Porque el idioma castellano es bastante prolijo…) que como podemos ver funciona con PHP 4 y pues va a ser que ya está descontinuado (incluso tienen un avisito recomendando el proyecto que vemos hoy acá).

Basado en ello S.C. Chen (me578022@gmail.com) programó una versión actualizada y basada en DOM con ayuda de Yousuke Kumakura y publicada en SourceForge, un alojador de contenido de software de código abierto que alberga más de 430.000 proyectos (3,7 millones de usuarios y 42 millones de clientes). Solo sabemos que S.C Chen es famoso a nivel mundial por su ópera prima que trajimos en este momento a colación.

Core DOM.

(pronto desarrollaremos este tema).

XML DOM.

Para poder entender el HTML DOM debemos primero estudiar y aprender el XML DOM y a continuación haremos nuestro racionamiento y sustento.

Concepto de XML.

“eXtensible Markup Language” o Lenguaje de Marcado Extensible (lo siento por el castellano pero lo seguiremos identificando como XML dado su impacto de facto en el mundo entero) es un lenguaje que “describe” como hacer las cosas y que además se puede ampliar en cualquier momento conservando una retrocompatibilidad. Fue diseñado para almacenar y transportar datos y que, además, pudiera ser leído por ordenadores y humanos por igual.

Si queréis leer sobre nuestra disertación acerca de lo que es un lenguaje de marcado, os invitamos a leer nuestro tutorial en línea sobre HTML. XML es guardado en ficheros codificados, generalmente, en UTF-8 para lograr compatibilidad con los diversos idiomas del mundo, nuestro tutorial sobre HTML5 también habla  y describe al respecto en forma detallada.

Normas XML.

Hay unas normas destacadas que mencionaremos y que a futuro, en la medida que tengamos tiempo para ello, le publicaremos sus diferentes entradas en nuestro humilde blog.

  • XML AJAX
  • XML DOM
  • XML XPath
  • XML XSLT
  • XML XQuery
  • XML DTD
  • XML Schema
  • XML Services

¿Qué es y qué NO es XML?

Aparte de lo que ya definimos, hay otros detalles que decir acerca del XML: fue diseñado para ser autodescriptivo, ya que a diferencia del HTML tiene muy pocos “comandos” o etiquetas y el XML como tal no hace absolutamente nada por sí solo. Esa es entonces la principal diferencia con HTML, que se enfoca en presentar los datos mientras que XML se enfoca en transportar datos.

Decimos que se puede extender ya que nosotros mismo “inventamos” nuestros propias etiquetas, así que no tenemos limitación pero una vez hallamos agregado más etiquetas a una información preexistente ésta seguirá siendo completamente leída y manipulada por distintas aplicaciones sin ningún tipo de problema.

Por supuesto, hacemos la advertencia que hablamos de extender, no de contraer: al eliminar algún dato por supuesto que las aplicaciones ya no podrán realizar su trabajo completo, y en muchos casos se negarán a realizarlo de plano.

Elementos de un documento XML.

Un documento XML está constituido por un elemento raíz el cual tiene elemento ramas o nodos que a su vez pueden contener subelementos y así sucesivamente. Cada elemento a su vez puede contener atributos.

De manera obligatoria un documento XML debe tener un elemento raíz, y aunque un prólogo no es obligatorio ni forma parte del documento es muy recomendable agregarlo; siempre va al principio del documento.

La función del prólogo es denotar la versión XML del documento y, de manera adicional, la codificación de caracteres el cual ya dijimos UTF-8 es lo más recomendable. La sintaxis del prólogo comienza con un símbolo “menor que” o mejor dicho, un corchete angular de apertura, ya que no estamos hablando de matemáticas en este caso (pero ayuda muchísimo a entender el concepto de aperura y cierre). Debe cerrar con un símbolo “mayor que” o corchete angular de cierre. Además de los dos símbolos anteriores se necesitan dos signos de interrogación de cierre y los contenidos deben estar entrecomillados para lo cual recomendamos las comillas simples, esto nos ahorra problemas para cuando vayamos a programar. Veamos un ejemplo de prólogo:

<?xml version='1.0' encoding='UTF-8'?>

El prólogo es un caso especial, y ya dijimos que no forma parte del documento, por lo tanto tiene distintas reglas que las aplicadas a los elementos, los cuales pasamos a describir en la siguiente sección.

Sintaxis de los elementos XML.

  • Cada uno de los elementos debe tener su correspondiente cierre pero con una barra invertida, por ejemplo:
    • <elemento> texto </elemento>
  • Los nombres de los elementos distinguen mayúsculas de minúsculas por lo tanto <elemento> no es igual a <Elemento>.
  • Los nombres de los elementos deben comenzar con una letra o en su defecto con un guion bajo ” _ “.
  • Los nombres de los elementos no pueden comenzar con “XML” o sus combinaciones de mayúsculas y/o minúsculas.
  • Los nombres de los elementos no puden contener espacios (de hecho un espacio denota que comienza un atributo, por eso no pueden contener espacios).
  • Los subelementos deben estar correctamente anidados dentro de los elementos, ejemplo:
    • <elemento><subelemento>valor</subelemento><elemento>
  • Los atributos de los elementos deben estar entrecomillados (lo mismo que dijimo para el prólogo se aplica en este caso), ejemplo:
    • <elemento principal=’si’> dato </elemento>
  • Como tal vez hayan captado, hay unos caracteres especiales en los documentos XML que no podremos usar directamente porque se presta a confusión para los ordenadores a la hora de leer el documento XML por lo tanto debemos sustituirlos por otros caracteres si queremos usarlos como datos:
    • Corchete angular de apertura “<” lo sustituimos por “&lt;” (recordad “lt”= “less than”, menos que).
    • Corchete angular de apertura “>” lo sustituimos por “&gt;“(recordad “gt”= “greater than”, mayor que).
    • Ampersand o “et” (proviene del latín, como en “etcétera”): “&” lo sustituimos por “&amp;“.
    • Apostrofo ” ” lo susituimos por “&apos;“.
    • Comillas dobles ” ” las sustituimos por “&quot;” (“quotation mark”).
  • Si queremos o necesitamos dejar un comentario para nosotros los seres humanos y que sea ignorado por el ordenador hacemos lo mismo que en el lenguaje HTML, lo encerramos entre los siguientes signos:
    • <!– comentario –>
    • Nota: dentro de un comentario no podemos escribir dos guiones juntos ya que dos guiones juntos indican inicio y fin de comentario, así que se prestaría a confusión para los ordenadores.
  • En los documentos XML debemos tener en cuenta que todo espacio es considerado como tal, es decir, los espacios se conservan y son un dato en sí mismo y así será leído ya quedará de parte de la aplicación el cortar o comprimir espacios “innecesarios”. Este comentario lo hacemos porque los documentos XML pueden ser leídos -y editados- por nosotros los humanos y un espacio en blanco mal colocado de nuestra parte hará que la aplicación que va  a leer los datos le suceda una excepción pero nosotros no veamos el error al abrir el archivo nosotros mismos.
  • Parecerá una tontería pero el caracter que indica el final de una línea es el caracter LF o “Line Feed” OSEA al caracter ASCII 10 y debemos tener siempre presente que en el sistema operativo Windows se utiliza LF más CR (ASCII 10 y 13 respectivamente) y en los viejos sistemas operativos Mac solo CR.

Características de los elementos de un documento XML.

  • Un elemento comienza desde el primer corchete angular de apertura hasta el último corchete angualr de cierre.
  • Un elemento puede contener:
    • Nada (pues eso, vacío, ni siquiera un espacio -si tuviera un espacio no sería vacio-).
    • Ya que introducimos el concepto de elemento vacio -y esto debería estar en la sintaxis- un elemento tácitamente vacio lo podremos denotar de la siguiente manera y ambos son iguales y válidos:
      • <elemento />
      • <elemento></elemento>
    • Texto -datos, para los ordenadores-.
    • Otros elementos -recordad anidar correctamente-.
    • Cualquier combinación de los tres anteriores, las combinaciones son infinitas y por ende decimos que son extensibles -y retrocompatibles-.

Una breve aclaratoria sobre los atributos.

Hay que tener especial cuidado con los atributos que le coloquemos a los elementos. Para no caer en abstracciones les haremos un caso práctico: consideremos un elemento llamado “persona” y lo que eso significa para nosotros los castellanohablantes.

<?xml version='1.0' encoding='UTF-8'?>
<persona></persona>

Ahora consideremos colocarle un atributo de género femenino o masculino:

<?xml version='1.0' encoding='UTF-8'?>
<persona sexo='masculino'>
    <nombre>Pedro</nombre>
</persona>
<persona sexo='femenino'>
   <nombre>María</nombre>
</persona>

Como vemos podemos “cargar” en memoria de ordenador solamente los hombres -o las mujeres- pero la aplicación que lee dichoa rchivo debe estar programada, de manera previa, a buscar esos dos géneros solamente ¿Qué sucedería si surgiera un tercer tipo de sexo, como por ejemplo hermafrodita?

<?xml version='1.0' encoding='UTF-8'?>
<persona sexo='masculino'>
    <nombre>Pedro</nombre>
</persona>
<persona sexo='hermafrodita'>
 <nombre>Michelle</nombre>
</persona>
<persona sexo='femenino'>
   <nombre>María</nombre>
</persona>

No habría forma ni manera que la aplicación pudiera “ampliarse” para que leyera datos adicionales ampliados, así que es una mejor idea plantearlo de la siguiente manera:

<?xml version='1.0' encoding='UTF-8'?>
<persona>
    <sexo>masculino</sexo>
    <nombre>Pedro</nombre>
</persona>
<persona>
    <sexo>hermafrodita</sexo>
    <nombre>Michelle</nombre>
</persona>
<persona>
    <sexo>femenino</sexo>
    <nombre>María</nombre>
</persona>

Como veís, colocado de esta manera la aplicación puede ir generando una matriz con los distintos nuevos tipos de valores tal como lo hace con los valores en sí mismos. Aparte de esta ventaja debemos recordar también que los atributos NO pueden contener múltiples valores y tampoco pueden tener estructuras tipo árbol, entonces ¿para que diantres sirven los atributos? Antes de responder esta pregunta queremos dejar en claro algo más sobre los atributos: los atributos son elemento fuertemente tipados -como decimos en los lenguajes de programación-, son estructura rígidas que son difíciles de cambiar a futuro pero que debido a esto podremos tomar ventaja; veamos la siguiente sección.

Eliminando ambigüedades en el nombrado de los elementos.

Como ya bien sabemos los documentos XML nos sirven para almacenar datos y debido a que nosotros los seres humanos asignamos un nombre para todo en nuestro universo -y a medida que lo seguimos descubriendo- no siempre escogemos nombres únicos. Tomemos por caso la palabra “banco”: tal vez primero pensemos en una institución financiera pero es que también un “banco” es un objeto sobre el cual podemos sentarnos.

Si por alguna idea peregrina nos damos a la tarea de guardar datos de ambos conceptos en un mismo documento XML debemos hallar una manera de diferenciarlos para que no haya lugar a dudas. Para ello podemos -y debemos- asignar un prefijo para eliminar cualquier duda, pero ¿qué prefijo usaremos? Pongamos por caso que los bancos -instituciones financieras- le colocamos el prefijo “i:” y los bancos -objetos- los prefijamos con “o:” (notemos que no violan la sintaxis de nombres de elementos ya que comienzan con una letra, no comienzan con “xml” ni contiene espacios):

<?xml version='1.0' encoding='UTF-8'?>
<raíz>
    <i:bancos>
        <i:nombre>Banco de Venezuela</i:nombre>
        <i:nombre>Banco Mercantil</i:nombre>
        <i:nombre>Banco Bicentenario</i:nombre>
    </i:bancos>
    <o:bancos>
        <o:nombre>banco de madera</o:nombre>
        <o:nombre>banco de metal</o:nombre>
        <o:nombre>taburete</o:nombre>
    </o:bancos>
</raíz>

Rapidamente notamos, si fueramos un lector ajeno que recibiera este documento XML, ¿qué diablos significa ambos prefijos, aparte de separarlos sintacticamente? Bien podríamos colocar un comentario para hacer alusión a qué nos referimos (“i:”institución financiera, “o:”obejto), pero eso funciona solo para nosotros los humanos, los ordenadores obvian estas observaciones ¿qué otra solución podemos echar mano?

Espacios de nombres en XML: XMLNS.

Los espacios de nombres (“Name Spaces”) en XML (juntos serían XMLNS) es el concepto para definir los prefijos que querramos usar en cualquier documento XML. Este “Name Spaces” son unos atributos y como tales debemos colocarlos en el elemento “padre” con un valor bajo la forma de URI (Uniform Resource Identifier) que bien puede ser a su vez un URL (Uniform Resource Locator) o un URN (Uniform Resource Name).

Para este nuestro caso vamos a usar el modelo de comentario y el modelo de URL todo esto apuntando siempre a que sea un ser humano el que va a leer la información (y luego veremos el caso de si es un ordenador el que “procesará” la información):

<?xml version='1.0' encoding='UTF-8'?>
<!--
  prefijo 'i:' se refiere a instituciones financieras.
  prefijo 'o:' se refiere a muebles, objetos.
-->
<raíz>
    <i:bancos xmlns:i='https://es.wikipedia.org/wiki/Banco'>
        <i:nombre>Banco de Venezuela</i:nombre>
        <i:nombre>Banco Mercantil</i:nombre>
        <i:nombre>Banco Bicentenario</i:nombre>
    </i:bancos>
    <o:bancos xmlns='https://es.wikipedia.org/wiki/Banco_(mueble)'>
        <o:nombre>banco de madera</o:nombre>
        <o:nombre>banco de metal</o:nombre>
        <o:nombre>taburete</o:nombre>
    </o:bancos>
</raíz>

También podemos declarar dichos atributos en el elemento raíz para darle mayor claridad a nuestro código y es igualmente válido:

<raíz
    xmlns:i='https://es.wikipedia.org/wiki/Banco'
    xmlns='https://es.wikipedia.org/wiki/Banco_(mueble)'
>

Recordemos que los documentos XML permiten los espacios en blanco para precisamente indentar para clarificar, por ello este formato de elemento raíz.

HTML DOM

Fuentes consultadas.

En idioma castellano.

En idioma inglés.

PMWiki tutorial

En el MarkDown tutorial que hicimos explicamos de manera rápida la manera de escribir una página web con un formato desenfadado y sin tantas pretensiones. También publicamos acerca de Marp, un software libre capaz de realizar presentaciones y exportar a PDF a partir de un fichero hecho con MarkDown. Analizando el software de familias Wikis nos topamos con PMWiki que tiene una peculiar manera de escribir código “pseudo HTML” y por ello comenzaremos explicando las reglas de sintaxis y luego veremos como se instala y mantiene una página web con dicha solución en software libre, ¡adelante!

PMWiki text markup.

PMWiki utiliza un lenguaje de marcado a diferencia del paradigma actual del siglo XXI: «lo que usted ve es lo que obtiene» (“What You See Is What You Get” o por sus iniciales WYSIWYG). Esto último consiste en utilizar herramientas de modelado que presentan en tiempo real la apariencia del trabajo que hacemos sin importarnos cómo se logra ya que el “interprete” nos abstrae del código subyacente. El asunto es que nosotros nunca dejamos de estar conscientes que los ordenadores solo entienden de unos y ceros (y ni siquiera eso, ya que es una abstracción que nos hacemos: solo entiende con apagado o encendido, hay o no hay en el último de los casos).

Reglas básicas de edición en PMWiki.

Hay seis reglas básicas para editar las páginas web cuyo motor web es la PMWiki:

  1. Para comenzar un párrafo solo basta con una simple línea en blanco.
  2. Para comenzar una lista enumerada comenzamos cada línea con un caracter numeral”#”; una lista no enumerada cada línea utiliza un asterisco “*” (numerada NO quiere decir ordenada, cuidado con los “falsos amigos” en las traducciones del inglés al castellano).
  3. Para un título principal comenzamos cada línea con signo de cierre de admiración “!” seguido de un espacio y luego el texto deseado. Cada subtítulo lleva dos o más signos de cierre de admiración “!!”, “!!!”, etc.
  4. Para texto en cursivas lo encerramos con dos comillas simples (”) y para texto en negritas tres comillas simples (”’).
  5. Para realizar un enlace web en nuestra propia wiki lo encerramos con dobles corchetes rectos “[[ nombre ]]” donde nombre es el archivo que contiene nuestra página, en realidad es un enlace relativo (muy útil si luego queremos “mudar” nuestra wiki).
  6. Si queremos enlaces web hacia otros sitios web también lo encerramos entre corchetes rectos doble y debemos escribir el enlace completo -vamos, dejad la pereza, escribid con todo y “http://“. También sirve para otros tipos de enlaces como el usado para enviar correo electrónico “mailto:“.

Párrafos y saltos de líneas.

Los párrafos se delimitan dejando una línea en blanco, por lo tanto todo lo que escribamos en varias líneas será presentado como un solo párrafo. Para los que amamos el utilizar la venta terminal para trabajar nos ofrece la ventaja de escribir con un máximo de 40, 80 o 90 caracteres de anchura lo cual nos permite una cómoda edición sin preocuparnos del ancho de pantalla que utilizarán nuestros usuarios.

papel pijama
papel pijama

Generalmente monitores con relación 16:9 que es apto para ver películas pero incómodo para ver párrafos muy anchos ya que dificulta seguir la línea que estamos leyendo -recordad el famoso papel pijama del siglo XX , pero bueno, ese no es nuestro problema sino del usuario de la página, je, je, je 🤓 ).

Este párrafo aunque
tiene varias líneas
será mostrado como uno solo.
Este párrafo aunque tiene varias líneas será mostrado como uno solo.
Para unir una línea con otra \
usaremos la barra invertida \
(a pesar que este es el comportamiento \
predeterminado, unir líneas).
Para unir una línea con otra usaremos la barra invertida (a pesar que este es el comportamiento predeterminado, unir líneas).
Sin embargo, si necesitamos que el párrafo
tenga múltiples líneas,
como por ejemplo un diálogo,
debemos usar al final dos barras
invertidas en cada línea, ejemplo: \\
-"¿Qué dijo ella acerca del tema?". \\
-"Que eso no era problema de ella". \\
Sin embargo, si necesitamos que el párrafo tenga múltiples líneas, como por ejemplo un diálogo, debemos usar al final dos barras invertidas en cada línea, ejemplo:
-"¿Qué dijo ella acerca del tema?".
-"Que eso no era problema de ella".
Para forzar fin de línea y dejar
una línea de por medio \\\
usamos tres barras invertidas.
Para forzar fin de línea y dejar una línea de por medio


usamos tres barras invertidas.
Para forzar la separación de una línea
usaremos [[<<]] para indicar el corte.
Para forzar la separación de una línea usaremos
para indicar el corte.
Para indentar un párrafo
(que sirve para hacer citas o resaltar ideas)
usaremos "->"
"Citas Citables."
Mientras más guiones usemos más indentado el párrafo.
Para indentar un párrafo (que sirve para hacer citas o resaltar ideas) usaremos "->":
"Citas Citables"

Mientras más guiones usemos más indentado el párrafo.
Una cita que comienze con
una línea prominente es una
forma atractiva para ello
usaremos "-<"
"Cita con línea prominente muy larga para que se note"
Una cita que comienze con
una línea prominente es una
forma atractiva para ello
usaremos
"Cita con línea prominente
muy larga para que se note"
Para comentarios usaremos los
símbolos mayor que y menor
>>comment<<
este es un comentario
>><<
que por pares.
Para comentarios usaremos los
símbolos mayor que y menor
que por pares.

En la tabla anterior os mostramos de manera práctica los comandos y cómo se vería, sin embargo es un artilugio de programación que le hicimos a WordPress para ilustraros el temas, hay algunos detalles que no se ven igual en PMWiki (lo mejor sería hacer un subdominio y correr una pequeña wiki allí para que veaís bien claro el resultado).

Listas.

Ya sabemos que para hacer una lista debemos comenzar con un asterisco “*” cada línea, y si acaso quiséramos asignarle una numeración automática debemos usar un numeral “#”. Cualquier línea a continuación que NO comience con asterisco o numeral es implícito que finaliza la lista.

Acá ampliamos un poco con las sublistas: una línea que comienze con dos asteriscos (despúes de una línea que comienze con un asterisco) se visualiza como una sublista:

* Esta es una lista.
* Segundo elemento de lista.
** Comienza sublista.
** Segunda línea de sublista.

Producirá el siguiente resultado:

  • Esta es una lista.
  • Segundo elemento de lista.
    • Comienza sublista.
    • Segunda línea de sublista.

Se pueden combinar:

* Lista
## Sublista.
## Dos.
## Tres.

Salida:

  • Lista.
    1. Sub lista uno
    2. Dos.
    3. Tres.

Algo que gusta mucho a los autores es la numeración romana o con letras del abecedario, ya sea en maypusuculas o minúsculas; esto se logra colocando las siguientes palabras claves luego de el o los asteriscos y/o numerales de cada línea (por supuesto, no se mostrará al usuario dichas palabras claves al momento de “servir” el artículo wiki):

  • %roman%
  • %ROMAN%
  • %alpha%
  • %ALPHA%

Ejemplos de códigos:

* %roman% Lista con números romanos.
* Línea dos en números romanos.
## %ALPHA% Sublista con letras del abecedario en mayúsculas.
## Segunda línea de sublista.

Y arrojaría lo siguiente:

WikiSandbox listas con numeracion romana y alfabetica
WikiSandbox listas con numeracion romana y alfabetica

Estos “trucos” necesarios para mostrar en WordPress listas y sublistas a “nuestra manera personalizada”  tendrán su artículo aparte y será un complemento a nuestro tutorial HTML5 para no hacer ese tutorial más voluminoso de lo que ya es -y enseñar a usar WordPress, que ni un temita le hemos dedicado a nuestro “motor” de blog.

Este concepto de palabras claves se repite si debemos forzar la numeración u orden: “%item value= número%“.

También si queremos parar la numeración y reiniciarla solo debemos insertar una línea con la siguiente palabra clave: “[==]“:

# %item value=7000% Línea siete mil.
# Siete mil uno.
[==]
# Reinicia numeración.

Salida:

  1. Línea siete mil.
  2. Siete mil uno.
  1. Reinicia numeración.

Nota: el indentado que veís lo hace WordPress para alinear las listas con diferentes numeraciones, se agradece para nosotros los maniáticos del orden.

Listas con párrafos explicativos.

Para cada elemento de una lista podemos anexar un párrafo a continuación para ampliar o definir un concepto o descripción. El estilo indica que ha de ser lo más breve y conciso posible para mantener el panorama de la lista en sí misma. Dijimos que cualquier línea a continucación que NO comience con asterisco o numeral significa el fin de la lista pero he aquí que si una línea comienza con un espacio se considera esa línea como perteneciente al elemento de la lista que lo precede pero no se enumera -no es un elemento de la lista en sí-. Para lograr el indentado se debe finalizar la línea elemento de lista con “\\” (que aunque no es esctrictamente necesario, mejora el aspecto).

Un ejemplo:

'''Grandes venezolanos'''
* Simón Bolívar, Caracas 1783, Santa Marta 1830.\\
 ''«Llamarse jefe para no serlo es el colmo de la miseria»''.
* Francisco de Miranda, Caracas 1750, Cádiz 1816.
 ''«¡Le Venezuela est Blessée au coeur!»''.
* José Antonio Páez.

Produce lo siguiente:

Grandes venezolanos:

  • Simón Bolívar, Caracas 1783, Santa Marta 1830.

«Llamarse jefe para no serlo es el colmo de la miseria».

  • Francisco de Miranda, Caracas 1750, Cádiz 1816.

«¡Le Venezuela est Blessée au coeur!».

  • José Antonio Páez.

Línea horizontal.

Si escribimos el comando “—-” (cuatro o más guiones seguidos) en una sola línea de texto nos produce una línea horizontal gráfica que sirve para separar párrafos o denotar importancia como una advertencia -o el uso que queráis-.


Texto sin formato, tal cual.

Supongamos que en nuestra PMWiki queremos hacer un tutorial en castellano sobre todo esto que estamos explicando acá vía WordPress: para indicarle que no proceso nuestros código ejemplos y los muestre tal cual, cómo código que son debemos “escapar” el texto de código con “[@ texto código @]”. Puede ser utilizado para un párrafo completo o para una o más palabras en un párrafo.

Para un “escapado” estricto utilizamos “[= texto código =]”, la diferencia esta que con arroba se respetarán los saltos de líneas y espacios pero con el signo de igualdad se escribirá todo junto como un párrafo .

Texto con fuente monoespaciada.

Si además necesitamos una fuente monoespaciada, es decir, un tipo de fuente cuyas letras todas y cada una tienen el mismo ancho simplemente debemos comenzar la línea con un espacio (que no esté después de una lista, ojo con eso). Imaginad (o recordad) los famosos cuadernos cuadriculados para matemáticas, una letra por retícula.

cuaderno cuadriculado
cuaderno cuadriculado

Tablas.

Para las tablas emplearemos el caracter doble “tubería” o “||”:

  • La primera línea con doble tubería seguido del tipo de borde: “|| border=1”.
  • La segunda línea con la primera fila de la tabla y cada elemento de columna separado con doble tubería.
  • Si es un encabezado de tabla, luego de doble tubería un signo de admiración de cierre.

Una tabla sin borde se logra con “border=0”, de uno en adelante produce un borde doble con un sombreado que aumenta según aumenta el valor entero que le demos.

Existe una sintaxis alterna para tablas más avanzadas pero en honor a la verdad dicha sintaxis es igual de compleja que escribir en código HTML. Pensamos que solamente vale la pena para un cuadro de navegación como el siguiente:

(:table border=1 width=30% align=right bgcolor=#cccc99 cellspacing=0 : )
(:cellnr: )
'''Páginas de buscadores'''
(:cellnr: )
*[[https://duckduckgo.com/ | DuckDuckGo]]
*[[https://fr.wikipedia.org/ | Wikipédia L'encyclopédie libre]]
(:tableend:)

En esta imagen podemos ver la tabla avanzada mezclada con los ejemplos últimos, debajo de la imagen coloamos TODO el código completo que produce ese resultado en PMWiki:

PMWiki formatos de texto listas y tablas
PMWiki formatos de texto listas y tablas
(:table border=1 width=30% align=right bgcolor=#cccc99 cellspacing=0 :)
(:cellnr:)
'''Páginas de buscadores'''
(:cellnr:)
*[[https://duckduckgo.com/ | DuckDuckGo]]
*[[https://fr.wikipedia.org/ | Wikipédia L'encyclopédie libre]]
(:tableend:)
'''Grandes venezolanos'''
* Simón Bolívar, Caracas 1783, Santa Marta 1830.\\
 ''«Llamarse jefe para no serlo es el colmo de la miseria»''.
* Francisco de Miranda, Caracas 1750, Cádiz 1816.
 ''«¡Le Venezuela est Blessée au coeur!»''.
* José Antonio Páez.
|| border=0
||! head 1 ||! head 2 ||! head 3 ||
|| cell 1 || cell 2 || cell 3 ||
|| border=1
||! head 1 ||! head 2 ||! head 3 ||
|| cell 1 || cell 2 || cell 3 ||
|| border=2
||! head 1 ||! head 2 ||! head 3 ||
|| cell 1 || cell 2 || cell 3 ||
|| border=3
||! head 1 ||! head 2 ||! head 3 ||
|| cell 1 || cell 2 || cell 3 ||

Nota: la tabla avanzada se colocará siempre a la derecha, tal como instruimos en código pero al mismo nivel de los elementos que tenga a continuación -uno al lado del otro-

Formato de caracteres.

Otros comandos nos permiten dar formato al texto para representar fórmulas, citas, etc

* Texto con '^superíndices^'.
* Texto with '_subíndices_'.
* Texto {-tachado-}.
* Texto {+subrayado+} (poco utilizado, se confunde con hipervínculo).
* Texto [+grande+], [++más grande++].
* Texto  [-pequeño-], [--más pequeño--].

En la siguiente sección colocamos una imagen tomada del WikiSandBox: es un área donde podremos libremente practicar nuestros códigos, podremos hacer y deshacer sin problema alguno, programamos y visualizamos resultado mientras agarramos práctica, la idea es luego escribir rápidamente artículos completos y publicar de una vez sin mayor dilación.

Sandbox” significa “cajón con arena” que nunca falta en los parques de los Estados Unidos y donde colocan a los pequeños y pequeñas para que desarrollen sus habilidades motoras sin peligro alguno; acá en Venezuela hacemos algo mucho mejor: los llevamos a las playas maravillosas de nuestro país.

Alineación de texto, color de fuente.

Por defecto el texto está alineado a la izquierda, pero podemos centrarlo comenzamos la línea con “%center%” y “%right%” para alinearlo a la derecha.

Para que el texto “flote” a la derecha sobre el siguiente párrafo que haya a continuación iniciamos con “%rfloat%” y si lo queremos en un marco “%rframe%“.

Para aplicar color simplemente escribimos el color, en inglés, encerrado entre signos de porcentaje. Esto se aplicará por defecto al resto del párrafo a partir del código, si necesitamos solamente colorear una palabra escribiremos “%blue% palabras a colorear %black%“. Por defecto el color de fuente es negro, por eso escribimos %black% pero eso no es necesariamente cierto, todo depende del estilo general de la PmWiki (tema avanzado). Lo correcto para restablecer el color es cerrar con doble signo de porcentaje “%%”.

También se pueden combinar los comandos, por ejemplo centrado y en color rojo: “%center red%”.

Formato de texto en WikiSandBox - PmWiki
Formato de texto en WikiSandBox – PmWiki

Alcance de los estilos.

No necesariamente se deben colocar los códigos al inicio de un párrafo, por ejemplo, a mitad de un párrafo podremos escribir “%p red% indicando que el párrafo, representado por la letra “p” sea rojo “red” sin importar dónde lo ubiquemos: al principio, en el medio o al final. Similar comportamiento aplica para otros elementos:

  • Imágenes: %img … (otros comandos)%
  • Texto de código: %pre (otros comandos)%
  • Lista: %list (otros comandos)%
  • Elemento de lista: %item (otros comandos)%

Estilos con nombres en castellano.

Podremos definir clases de estilos, definidos por nosotros mismos. En mejor uso es poder escribir en castellano, especialmente para aquellos u aquellas que no dominan ese idioma. Para ello al comienzo de un artículo podríamos escribir lo siguiente:

%define=amarillo color=yellow%
%define=fondo_amarillo bgcolor=yellow%
%define=azul color=blue%
%define=fondo_azul bgcolor=blue%
%define=rojo color=red%
%define=fondo_rojo bgcolor=red%

%amarillo%Conocerás los principios básicos%% de la programación en PHP como su sintaxis, estructuras de control, etc. %azul%Además explorarás un nutrido conjunto de características%% y funcionalidades, las necesarias para desarrollar la mayoría de las aplicaciones, %fondo_rojo%como el acceso a la base de datos%%, el sistema de archivos, etc.
Clases definidas en PmWiki
Clases definidas en PmWiki

Así entonces será más fácil recordar los comandos, pero supone escribir guiones al principio de cada artículo. Es mejor definir estilos globales, que funcionen en toda la página PmWiki alojada, eso es avanzado y más adelante lo estableceremos en la configuración de instalación.

Caracteres especiales.

Pues con nuestros teclados o copiando y pegando podemos escribir los caracteres “especiales”: las vocales acentuadas, el símbolo de la moneda euro €, etcétera y para ello rigen las mismas normas del HTML: la “á” se escribiría “&aacute;” el símbolo del €: &euro;.

Imágenes.

Por increíble que parezca, para mostrar una imagen en nuestra PmWiki simplemente colocamos el enlace hacia la imagen web… ¡y listo! (en WordPress es igual, aunque no lo creáis, pero este tutorial es de PmWiki y no otra cosa, disculpad).

El meollo del asunto es que normalmente gustamos de darle formato a las imágenes, texto alterno si el navegador no puede mostrar imágenes -o las tienen bloqueadas de alguna manera-, títulos, tamaños, bordes,  etc. Comencemos a realizar una lista con las principales características:

  • Comenzemos por establecer que una imagen ocupa una línea completa, imaginad que estamos escribiendo un párrafo. Luego cuando cojamos práctica podremos mezclar imagen entre párrafos para lograr bonitos acabados, verbigracia, como una enciclopedia merece; pero vayamos aprendiendo poco a poco.
  • Simplemente una imagen, sin más, colocamos una URL completa con alguno de los siguientes formatos de imágenes: gif, jpg, jpeg, png, svg, svgz. Dicha imagen debería residir en nuestro servidor por principios de ética de no “robar” el ancho de banda de los demás sitios web. Aunque PmWiki permite subir imágenes, dicha función, por seguridad, viene desactivada por defecto. En la sección de instalación y configuración tomaremos de nuevo el tema.
    • Ejemplo de imagen:
      1
      http://pmichaud.com/img/misc/pc.jpg
    • La anterior imagen está alojada en el servidor web del autor de PmWiki, el Doctor Patrick Michaud, la imagen fue tomada de Flickr y tiene licencia “Creative Commons”.
  • Cuando uno ubica, sin hacer click, el puntero del ratón (y nos disculpáis la redundancia) sobre una imagen web por más de 500 milisegundos (generalmente) nos aparece una ventanita con un texto que describe la imagen: para lograrlo en PmWiki debemos escribir a continuación y sin dejar espacio alguno, encerrado entre comillas dobles el texto deseado. También este texto es mostrado si por razón alguna el navegador NO puede mostrar la imagen, y los navegadores web modernos que narran las páginas web también toman este texto para los discapacitados visuales.
    • Ejemplo de “tooltip”: http://pmichaud.com/img/misc/pc.jpg”CLIPS”
  • Si queremos establecer un título a la imagen, después de las comillas dobles y sin espacio alguno insertamos un caracter “tubería” “|” e inmediatamente el texto deseado. En honor a la verdad si acepta espacios entre el caracter tubería pero recomendamos escribir todo junto para ayudarnos a recordar el proceso (y pulsar menos teclas para escribir más rápido).
    • Ejemplo de título a imagen: http://pmichaud.com/img/misc/pc.jpg”CLIPS”|”Clips coloridos”
  • Si queremos que la imagen en sí sea un enlace web debemos prestar mucha atención: debemos encerrarla entre corchetes rectos dobles pero dejando fuera el título de imagen, si es que la hubiere.
    • Seguimos con el mismo ejemplo, ahora más larga la línea:
    • [[http://pmwiki.org/|http://pmichaud.com/img/misc/pc.jpg”CLIPS”]]|”Clips coloridos”
  • Al igual que un texto, podemos alinear la imagen al centro o derecha colocándole de principio de línea los comandos %center% o %right% (por defecto se alinea a la izquierda):
    • %center%[[http://pmwiki.org/|http://pmichaud.com/img/misc/pc.jpg”CLIPS”]]|”Clips coloridos”
    • Ahora vamos viendo el porqué recomendamos eliminar los espacios, va larga la cosa. 🙂
  • Hasta ahora la imagen que queremos mostrar es tal cual, sin ninguna modificación al tamaño. Rogamos encarecidamente que subáis imágenes ligeras, en formato jpg preferiblemente y que midan menos de 50 mil bytes. Para redimensionar debemos usar:
    • A un ancho específico: %width=150px% (a 150 píxeles de ancho).
    • A un alto específico: %heigth%=100px% (a 100 píxeles de alto).
    • A una miniatura (66 x 32 píxeles, formato gif): %thumb%.
    • Intentamos seguir con el ejemplo planeado pero las múltiples combinaciones impiden que PmWiki redimensione la imagen, bien puede ser un excepción de PmWiki o nosotros desconocemos la sintaxis correcta pero nos decantamos -humildemente- por el error “bug” de PmWiki.
  • Para que al hacer click en la imagen se abra en una pestaña o ventana nueva debemos encerrar todo el enlace y sus opciones adicionales entre “%newwin% enlace_web %%” teniendo la precaución de colocarlo todo junto y justo antes de los corchetes dobles. Si quisieramos centrar la imagen primero debemos escribir %center% y luego el resto del comando y no al revés porque no lo tomara de forma debida y esperada.
  • Un interesante efecto para un párrafo es insertar la imagen a la izquierda o a la derecha de un párrafo que la describa o hable de ella, para lograr esto simplemente colocamos %rframe% o %lframe% antes del código de la imagen y luego al finalizar el código en otra línea el párrafo, sin dejar líneas vacías de por medio.
    • %rframe%http://www.ks7000.net.ve/wp-content/uploads/2017/05/PmWiki-logo-1.jpg párrafo
    • De nuevo, las opciones de redimensionamiento tampoco logramos hacerlas funcionar con %rframe%.
    • Imagen en cuadro flotando sobre texto alineado a la derecha
      Imagen en cuadro flotando sobre texto alineado a la derecha
  • Existen muchísimas más opciones para elt ratamiento de imágenes pero escapan a la simplicidad que queremos lograr y se aproximan más a la sintaxis de CSS y HTML, y es justo lo que queremos evitar, escribir en esos dos lenguajes de marcado.
  • Las imágenes se pueden combinar con tablas pero de nuevo, no son nada sencillo y queremos evitar su uso.
  • PmWiki es tan poderoso como queráis, no lo subestiméis, al modificar “config.php” tendremos cientos de personalizaciones, pero mantengamos la simplicidad, por favor -no todos nuestros usuarios serán tan avanzados en programación, con que aprendan unos cuantos comandos bastará para que escriban en nuestra Wiki.

Historia de PmWiki.

La palabra wiki proviene del idioma hablado en la isla de Hawaii, quincuagésimo estado federal de los Estados Unidos de América. Significa rápido y wiki wiki súper rápido (ya en los años 80 acá en Venezuela vendíamos un tinte para ropa llamado “wiki-wiki”: no teníamos dinero para comprar pantalones nuevos y los pintábamos de negro y listo, “pantalones nuevos” rápidamente).

Las páginas web que tienen un motor wiki son como cualquier otra página web pero tienen dos características únicas:

  • Tienen un botón con la palabra “editar” para que cualquiera colabore en ellas (y podemos subir o bajar los requerimientos de seguridad en la medida que nos sintamos cómodos).
  • No se necesita de conocimientos profundos sobre desarrollo web, con unos cuantos comandos como los que vimos arriba en el resumen de 6 pasos bastan para que se comienze a plasmar el aporte de cada quien.

Autor de PmWiki.

El caso concreto de PmWiki el Doctor Patrick Michaud (la letra “d” NO se pronuncia) es el autor con más de 40 años de experiencia en computación (graduado con “Post High Degree” en la University of Southwestern Louisiana -aquí le decimos Doctorado-) y podéis acceder a su página web http://www.pmichaud.com/ donde, faltaría más, faltaría menos con el motor PmWiki donde mantiene un resumen de su vida profesional y formas de contactarlo ya sea por correo eletrónico o redes sociales.

Dr. Patrick Michaud
Dr. Patrick Michaud

Filosofía de trabajo de PmWiki.

Fueron establecidas durante el desarrollo de PmWiki y aunque el Dr. Michaud comparte muchas de ellas no son exclusivas de su persona, de hecho mantienen un foro abierto a nuevas ideas y sugerencias para mantener activo este software a los requerimientos modernos de la humanidad.

Los pilares son:

  1. Preocupados sobre los autores más que por los lectores: buenos autores son difíciles de conseguir y “mantenerlos” en el proyecto priva sobre cualquier lector de la enciclopedia (crudo pero es la realidad).
  2. PmWiki no trata de reemplazar al HTML: ya hemos hablado sobre esto, se enfoca en ser algo simple y sencillo para los autores, sin embargo tiene poderosos sustitutos que pueden llegar a realizar casi lo mismo que el HTML pero no es nunca ese su objetivo.
  3. Pragmatismo sobre todo: se busca la utilidad por encima de la moda, algo bien estructurado en vez de ir a lanzarse a la primera por cualquier tendencia.
  4. Soporte colaborativo para el mantenimiento público de páginas web: autores y grupos de autores pueden ir construyendo un sitio para luego llegar a un punto de madurez y empezar a proteger con contraseñas ya sean páginas individuales o secciones o grandes secciones que busquen preservar los títulos, subtítulos e incluso párrafos e imágenes mientra otras áreas están libres y abiertas para captar nuevas ideas o registrar el simple pasar del tiempo. Precisamente éste es un ejemplo: un registro de cambios de un artículo (NO el registro de cambios de la página en sí) debería estar protegido al cabo de cierto tiempo, días o semanas, proque eso es historia y ya no cambiará (incluso se pueden dejar las referencias abiertas en pie de página si alguien quiere agregar algo al tema).
  5. Fácil de instalar, configurar y mantener: del dicho al hecho, las siguientes secciones hablan sobre ello.

Instalación de PmWiki.

Primero debemos descargarlo de forma comprimida desde PmWiki, solo pesa menos de medio megabyte, la versión estable 2.2.98 -ya os dijimos: PmWiki es sencillo y simple pero muy útil-.

Como un servicio a la comunidad por acá también la ponemos a la orden, si la queréis descargar desde acá.

Se ofrece paquetes adicionales para diferentes idiomas en esta dirección de la misma PmWiki.org pero deja mucho que desear por ahora para nuestro trabajo la vamos a dejar así, en purito inglés pero no creáis que nos hemos rendido con el castellano, de hecho tenemos en mente unas ideas laboriosas por realizar y una vez terminemos la publicaremos por acá.

Una vez descargado lo descomprimimos en nuestra carpeta /var/www/html -en nuestro caso usamos un servidor web Apache2 con PHP5 en nuestro ordenador en VirtualBox- y debemos darle los derechos adecuados de escritura para que se puedan grabar nuestras preferencias.

Se recomienda crear una carpeta llamada pmwiki en la carpeta pública de nuestro servidor web y redirigir debidamente modificando el .htaccess (o por otros métodos). No es la tarea de esta entrada y tomando en cuenta que tenemos un servidor de pruebas y por propósitos didácticos NO LO HAREMOS ASÍ sino que simplemente colocaremos los ficheros y directorios como si el servidor fuera dedicado a retribuir una sola página web.

Ficheros y carpetas de PmWiki.

Una vez hayamos copiado los archivos tendremos la siguiente estructura que pasamos a traducir directo del propio tutorial en inglés:

  • README.txt: un documento introductorio y contiene la licencia de uso GNU:
  • pmwiki.php: el archivo principal, el hace las veces del “index.php” en nuestro servidor Apache2.
  • local/: Carpeta que contiene los guiones de configuración local.
  • cookbook/ : Carpeta con”recetario” con programas agregados que enriquecen a PmWiki (suplementos).
  • docs/ : Documentación y guiones de ejemplo.
  • pub/ : archivos de acceso público.
    • pub/css/ : Archivos con hojas de estilo en cascada de los temas (suplementos).
    • pub/guiedit/ : (¡aún no hemos estudiado este directorio!).
    • pub/skins/ : “temas” para cambiar la apariencia y comportamiento de PmWiki.
  • scripts/ : Guiones que son partes de PmWiki.
  • wikilib.d/: Paquete de páginas predeterminadas de PmWiki.

Por ahora esos son los ficheros y directorios iniciales, los cuales, por seguridad, solo necesitamos que tengan derecho de lectura más no de escritura. Para poder guardar nuestras configuraciones y futuros artículos debemos tener derechos de escritura en una carpeta especial llamada “wiki.d/“.

¡Atención! no confundir con la carpeta wikilib.d

  • Dentro de esta carpeta wiki.d se guardarán nuestros artículos con el prefijo “PmWiki.” más el nombre del título que le pongamos al crearla.
  • Junto a estos archivos automáticamente PmWiki llevará de manera sincronizada otros ficheros donde se registran los cambios hechos, la configuración de la barra lateral izquierda e incluso un índice de páginas. No debemos preocuparnos por estos archivos, excepto respaldarlos regularmente fuera de nuestro sitio web y/o servidor de producción (si respaldamos en nuestro ordenador podremos llevar un respaldo adicional junto con un control de cambios al utilizar GitHub el cual es sin costo para proyecto públicos -proyectos privados se paga mensual en US$-).
  • El otro directorio que debe tener derechos de escritura si es que llegamos a habilitarlo es la carpeta “uploads” que viene a albergar los ficheros que subamos a nuestro servidor. Se le harán las mismas consideraciones del punto anterior.

Si nuestro servidor permite acceso vía SSH por ventana terminal usaremos el comando “chmod” para otorgar permisos de escritura, si es un servidor web compartido generalmente tenemos acceso vía softwfare CPANEL que permite lanzar un navegador de archivos y otorgar derechos de escritura a esas dos carpetas. También recordemos que el comando “chmod” funciona en muchos programas clientes FTP, así que cuando “subamos” los archivos de PmWiki podríamos cambiar de una vez los derechos de escritura.

Dado el caso que NO hayamos configurado lo anterior y nos decidimos por ejecutar directamente de una el fichero principal pmwiki.php éste nos lo recordará amablemente con un mensaje de que no podemos seguir adelante.

Ejecutando por primera vez pmwiki.php

Pues bien, acá se mostrará la página de bienvenida con tutoriales e indicaciones -en inglés- de todo lo que explicamos acá en idioma castellano.

Estableciendo “index.php” o “index.html”

Dependiendeo de como tengáis configurado vuestro servidor, necesitaréis un archivo llamado “index.php” o si tenéis configurado tratar los archivos con extensión .html como .php debeis escribir en él lo siguiente:

1
2
3
4
&lt;?php
include("pmwiki.php");

?&gt;

Modificando “config.php”.

Lo que nos toca por hacer es configurar el archivo config.php en la carpeta “local/“. Dicho archivo es de solo lectura pero debemos tener permisos de escritura para copiarlo desde la plantilla llamada “sample-config.php” (carpeta “docs/”) la cual modificaremos a nuestro gusto y conveniencia: en nuestro ordenador donde hayamos descargado y descomprimido PmWiki copiamos el archivo con el nombre “config.phplo modificamos para luego subirlo (vía https o sftp) a nuestra carpeta “local/”.

Este fichero contiene las configuraciones comunes pero vienen inactivas gracias a un caracter numeral al principio de cada línea de comando, eliminando dicho caracter las “descomentamos” y ponemos a nuestro servicio.

  • La primera línea que modificaremos es el título de nuestra página, por defecto reza “$WikiTitle = ‘PmWiki’;” cambiando solamente lo que está entre comilla simples.
  • La segunda línea a cambiar permite cambiar nuestro logotipo a una imagen tipo gif de 32 píxeles que diseñemos y con el nombre que querramos, cambiamos la siguiente línea QUE DEBEMOS DESMARCAR como comentario (fijaos en la ruta donde vamos a subir dicho archivo):
    • $PageLogoUrl = “$PubDirUrl/skins/pmwiki/pmwiki-32.gif“;
  • ¡Muy importante! la contraseña administrativa en la línea siguiente la cambiaremos a nuestro criterio:
    • $DefaultPasswords[‘admin’] = pmcrypt(‘secret‘);
  • Si quisieramos activar la subida de archivos, modificar la línea que activa (descomentarla) y fijar una nueva contraseña a nuestra conveniencia (y descomentarla también):
    • $EnableUpload = 1;
    • $DefaultPasswords[‘upload’] = pmcrypt(‘secret‘);
  • PmWiki permite unos botones gráficos para darle un pequeño toque “colorido” a nuestra página web, si deseais lo activaís descomentando la siguiente línea:
    • $EnableGUIButtons = 1;
    • PmWiki botones gráficos
      PmWiki botones gráficos

¡LISTO! Guardamos y copiamos a su ubicación final y vemos los cambios recargando la página.

Seguridad en PmWiki.

Al modificar config.php establecimos nuestra contraseña como administrador, nuestra llave para crear, modificar o  eliminar contraseñas, es el más alto nivel efectivo en nuestro sitio. La reservamos para nosotros, los programadores y encargados del mantenimiento y funcionamiento de la página web en sí ya que la mayor del tiempo serán los autores los que estarán a cargo de proteger sus propios trabajos.

El enfoque que utilizaremos, siempre pragmáticos, es de ir de menos a más, según nuestras necesidades, analizemos:

Grupo de 1 a 3 autores.

Siendo un grupo pequeño solo se necesita que a nivel global todos los botones de edición de página tengan una simple contraseña. Para lograr esto debemos descomentar y modificar (o agregar) la línea siguiente en /local/config.php

$DefaultPasswords['edit'] = pmcrypt('nuestra_contraseña_de_edicion');

Acá no hay más complicaciones, solo es cuestion de comunicarse entre ellos y verbalmente dirimir sus diferencias, en teoría no debería haber mayor problema y si lo hubiera nosotros como administradores deberemos tener la última palabra y “reiniciar” la contraseña a nivel global para excluir a algún miembro de la edición de artículos -caso extremo-. Luego veremos que tal vez tengamos unas tareas adicionales que realizar, tened paciencia y os explicamos, vamos a continuar con la idea de grupos.

Grupo de 3 a 12 autores.

Manejar a esta cantidad de personas la cosa se complica un poco. Tratar de reunirlos todos a la vez va a ser difícil y si se lograra se nos va a ir el tiempo en reuniones grupales, lo cual es mucho trabajo para el poco dinero que nos pagan por la tarea. 😉

El mejor enfoque en este caso es establecer nosotros mismos normas de publicación (grupo de páginas) de caracter privado por lo que tendremos que establecer contraseñas para poder leer este particular grupo de páginas. Establecidas las normas, ya saben a qué atenerse. Una vez “tamizados” los autores podremos elegir a dos sub administradores que nos ayuden en nuestro trabajo, pero ¿cómo lograr esto sin dar nuestra contraseña de edición a los subadministradores? A nivel global se pueden establecer matrices de contraseñas (esto ya es lenguaje PHP en sí) de nuevo en el ya famoso archivo config.php:

$DefaultPasswords['read'] = array(pmcrypt('alfa'), pmcrypt('beta'));
$DefaultPasswords['edit'] = pmcrypt('beta');

alfa” y “beta” serán dos contraseñas distintas, para elevar un autor a subadministrador (ojo, esta figura no está canonizada en el sistema PmWiki, la estamos “inventando” en este artículo práctico) pues le daremos una nueva contraseña que será “beta“. Es más, si son dos subadministradores, como proponemos ,nada nos impide generar una contraseña “gamma”:

$DefaultPasswords['read'] = array(pmcrypt('alfa'), pmcrypt('beta'), pmcrypt('gamma'));
$DefaultPasswords['edit'] = array(pmcrypt('beta'), pmcrypt('gamma'));

Luego veremos que tal vez tengamos unas tareas adicionales que realizar, tened paciencia y os explicamos, vamos a continuar con la idea de grupos.

Grupo de autores de hasta 100 autores.

Acá la cosa se pone “color de hormiga”: ya en este punto debemos habilitar usuario y contraseña (léase “login” y “password”) para todos y cada uno de los usuarios a fin de determinar quién hizo qué y tomar las medidas correspondientes. ¿Recordáis la figura de subadministradores? Pues bien, ¡vamos a necesitar entre 3 y 6! Esto es así porque el mantener cuentas y contraseñas de usuario se va a llevar bastante trabajo y necesitamos

El primer paso para habilitar esta característica es agregar (o descomentar) la siguiente línea en /local/config.php:

include_once("$FarmD/scripts/authuser.php");

Demás está decir que ya habremos establecido nuestra contraseña de “admin”, lógicamente, en vez de la que trae por defecto la instalación de PmWiki (un hacker -buenas intenciones- o un cracker -malas intenciones- lo primero que haría sería intentar entrar con esa contraseña por defecto).

La manera de registrar a los usuarios es editar una página llamada pmwiki.php?n=SiteAdmin.AuthUser, es decir, al guión principal llamado pmwiki.php le “pasamos” en la barra de direcciones un signo de cierre de interrogación y solicitará nombre de usuario y contraseña al editar (usaremos la superclave de admin) y agregaremos cada cuenta con la siguiente sintaxis:

nombre_de_usuario: (:encrypt contraseña🙂

Guardamos la página y la contraseña se mostrará encriptada. Dichas cuentas, por manía de orden, la colocamos justo después del subtítulo “Login accounts” y más abajo veremos el subtítulo “Authorization groups” donde podramos definir los grupos de usuarios que inventamos, a saber: autores y subadministradores.

@autores: Kevin, Jimmy
@subadministradores: Kevin

Al crear este tipo de grupos de usuarios se nos facilita enormente la tarea de administración si invertimos el enfoque: nombramos a cada usuario a los grupos que puede pertenecer, el ejemplo anterior pero por usuarios:

Kevin: @autores, @subadministradores
Jimmy: @autores

¿En qué nos beneficia todo esto? En que en cada página podemos definir cuales grupos tienen acceso e incluso podemos delegar -con sumo cuidado- de poder editar la mismísa página SiteAdmin.AuthUser. A primer vista esto parecería una locura pero es que para definir cuentas de usuarios y grupos de usuarios la otra manera de hacerlo permitir editar el fichero config.php y esto no es para que lo haga todo el mundo, cualquier cosa  podría salir mal y tendríamos nosotros mismo que enmendar el capote.

Luego veremos que tal vez tengamos unas tareas adicionales que realizar, tened paciencia y os explicamos, vamos a continuar con la idea de grupos.

Grupos de 100 o más autores.

Manejar tal cifra de personas ya no es posible hacerlo así, “de manera manual”, tendremos que recurrir al uso de protocolos y normas adecuados y que manejen bases de datos para llevar cuenta de todo. PmWiki ofrece acceso mediante el protocolo LDAP pero escapa al alcance de este tutorial. También existe apoyo para htpasswd: el cual utiliza el servidor Apache2 pero no supone ventaja alguna porque al igual que PmWiki se basa en texto plano -incluso encriptado- y no utiliza base de datos además deja por fuera a Ngix que es otro poderoso servidor web, así que no le vemos futuro a esa alternativa.

Además, para manejar tal cantidad de usuarios, se espera una gran cantidad de artículos y por ello debemos hacer uso de un manejador de base de datos que no exija demasiado recursos de cómputo: SQLite es el elegido para ello. Para habilitar su uso debemos descargar y ejecutar este guion creado por Petko Yotov con el cual creamos la base de datos, tablas, índices y relaciones y una vez hecho esto si que debemos modificar de nuevo el consabido config.php en alguna de sus primeras líneas lo siguiente:

1
2
3
4
5
6
7
include_once("$FarmD/cookbook/sqlite.php");
$WikiDir = new PageStoreSQLite($WorkDir.'/pmwiki.sqlite.db', 1);
$WikiLibDirs = array(
&amp;$WikiDir,
new PageStore('wiki.d/{$FullName}'),
new PageStore('$FarmD/wikilib.d/{$FullName}')
);

El fichero pmwiki.sqlite.db será entonces el único que conservará las página que creemos y será el que dabamos respaldar llegado el momento necesario. Esto apenas es un resumen ya que todo programador sabe muy bien que no hay base de datos “rebeldes” sino mal administradas. Por ejemplo, de tanto en tanto deberemos ejecutar la orden

1
pmwiki.php?action=vacuum

; también podremos establecer un valor automático para que ejecuta esta acción por nosotros si lo establecemos en config.php:

$SQLiteAutoVacuum = 300;

Incluso si le colocamos el valor de cero (no ejecutar), siempre podremos hacerlo cuando necesitemos con ?action=vacuum.

Tareas adicionales.

Pues que varias veces nombramos unas dichosas “tareas adicionales” que debíamos realizar para “cerrar el círculo de seguridad” para ello los siguientes datos:

  • Las páginas y grupos de páginas les pueden ser establecidas, individualmente,
    • Contraseña de lectura read.
    • Contraseña de escritura write.
    • Contraseña de acceso a configurar las dos anteriores mediante attr.
  • Para modificar las contraseñas de lectura y escritura a una página debemos adicionar “?action=attr” al final en la barra de direcciones y así introducir nuestra contraseña de administrador (admin).
  • Para modificar las contraseña de lectura y escritura a un grupo de páginas debemos adicionar al final en la barra de direcciones lo siguiente (susitutid “GroupName” por el nombre del grupo de páginas:)
    • ?n=GroupName.GroupAttributes?action=attr
  • Las contraseña son visibles para no pedir confirmación pero al ser guardadas serán debidamente encriptadas (cuidado con las miradas encima por encima de tus hombros).
  • En cada campo -lectura y escritura- de una página o grupo de páginas podremos:
    • Agregar una o más contraseñas simplemente separándolas por un espacio.
    • Agregar uno o más grupos nombrandolos precedidos de una arroba -ejemplo @subadministradores- y separándolos por un espacio entre ellos.
    • Si queremos que todos los miembros de un grupo tengan acceso usaremos “@nombre_grupo: *“.
    • Si de ese grupo necesitamos  exceptuar un usuario -que pertenece a ese grupo-:
      • @nombre_grupo: *, -nombre_usuario“.
    • Establecer uno o más usuarios con la palabra clave “id:” y a continuación los nombres de los usuarios deseados separados por comas.
    • Para incluir todos los usuarios: “id:*”
    • Dejar la contraseña en blanco no guarda los cambios para ese campo.
    • Si queremos quitar la(s) contraseñas debemos usar la palabra clave “clear” solamente.
    • Evidentemente ningún usuario podrá llamarse “clear” (no hemos probado si admite tal usuario)-
    • Si queremos dejar sin contraseña, así esté establecida a nivel global usaremos “@nopass” solamente.
    • Si al contrario, solo queremos que nosotros como administrador seamos los únicos con derechos sobre una página o grupo de páginas usaremos la palabra clave “@lock” solamente.
    • Si previamente aplicamos “clear” o “@nopass” podemos restaurar las contraseñas globales con las correspondientes a continuación: “@_site_edit“, “@_site_read” or “@_site_upload” (si este último está establecido).

Nosotros como administradores podemos…

  1. Establecer contraseñas globales para páginas y/o grupo de páginas que no tengan contraseñas.
  2. Usar attr para controlar quien es capaz de establecer contraseñas en las páginas.
  3. Si está habilitada las subida de archivos, establecer contraseñas para ello.
  4. Usar nuestra contraseña de administrador para eliminar o cambiar las contraseñas de lectura y/o escritura establecidas para cada página o grupo de páginas.
  5. Usar “SiteAdmin.AuthList” para visualizar las páginas o grupos de páginas que tengan contraseñas establecidas.

Jerarquía de contraseñas.

  • Las contraseñas de páginas privan sobre las contraseñas de grupos de páginas.
  • Las contraseñas de grupos de páginas privan sobre las contraseñas globales.
  • Las contraseñas de administrador privan sobre las contraseñas globales, contraseñas de grupos de páginas y contraseñas de páginas.

Tapando los agujeros de orden y seguridad.

  • Por  defecto cuando editamos una página es opcional el colocar nuestro nombres para indicar autoría, esto es especialmente útil si nuestra wiki está abierta a todo público, completamente libre. Pero si estamos en el punto de haber creado cuentas de usuario debemos obligar a que utilizen su nombre en cada edición, esto se logra en el archivo config.php:
    • $Author = $AuthId; # after include_once()
  • También podemos permitir al usuario escribir el nombre que desee pero siempre aparecerá primero un prefijo que lo identifica como autor. Esto es útil si el autor desea compartir su clave con otro autor que nosotros no hemos autorizado y se desea saber quien hizo qué. En todo caso el autor/usuario con la cual se modificó la página o grupo de páginas será plenamente responsable de dichos cambios, sin importar si otra persona lo hizo.
  • Otra forma más estricta es inhabilitar el campo “autor” en el formulario de edición de cada página, pero eso cierra la posibilidad de dejar abiertas ciertas páginas o grupos de páginas (partiendo del principio de que cada quien desea ser conocido por los cambios realizados).
  • Si tenemos varias wikis corriendo en un mismo servidor (diferentes dominios o subdominios) debemos decirle a PHP que cada wiki tiene su propia y particular sesión agregando al principio de config.php la siguiente línea (por supuesto, generad vuestr propia clave aleatoria, y una por cada wiki que tengáis):
    • session_name('XYZSESSID');
  • Podemos establecer varias contraseñas para ‘admin’ con array() en el archivo config.php recordando el habilitar cuentas de usuario y contraseñas, forzando el grabado de autorías (ver párrafos anteriores) para saber quién hizo qué.
  • Podemos predefinir los grupos de páginas que contendrá nuestra PmWiki (más bien muchos verán esto como una restricción pero todo está en el diálogo entre los autores) por medio de insertar en config.php la siguiente clave: “$GroupPattern = ‘(?:Sitio|PmWiki|Principal|Ventas|Compras)’;” y si necesitamos ampliarla pues le agregamos otro caracter tubería seguido de los nuevos grupos.

Manejando la “internacionalizaciones”.

Las llamadas “internacionalizaciones” (“i18s“por su abreviatura en inglés de las 18 letras -22 en castellano-) son las traducciones a otros idiomas de PmWiki. Como bien sabemos el lenguaje PHP fue escrito en idioma inglés y PmWiki no es la excepción. La solución que planteó el Dr. Patrick Michaud está plasmada en dos aspectos fundamentales: la traducción de los “diálogos comunes” y la creación por parte de la comunidad de las respectivas páginas “tutoriales” que describen la instalación, uso y mantenimiento de PmWiki. Por ello divideremos esta sección en dos temas “apartes”.

Traducción de los “diálogos comunes”.

En PmWiki “normalizaron” los diálogos comunes, que son las instrucciones que visualiza el usuario. Las más visibles de ellas son “View Edit History Print Backlinks” que vemos en la parte superior derecha de cada página. El mecanismo es el siguiente: existe un archivo principal, el núcleo o corazón de PmWiki llamado “pmwiki.php” el cual nuestro servidor web ejecuta y carga los diversos componentes -que no vienen al caso por la complejidad del asunto-.

Lo que queremos ejemplarizar es cuando se carga el archivo “Site.PageActions” en la carpeta wililib.d allí tenemos unos cuantos mensajes al usuario, uno de ellos un enlace para modificar la página que esté en ese momento visualizando, otro para ver su historial además de las paǵinas relacionadas (y hay más enlaces/opciones).

En forma de matriz llamada text() se cargan los diferentes mensajes predefinidos por una estructura (de nuevo, estamos simplifanco al máximo) hasta llegar a los simples mensajes que acompañan una “acción”, cargar pmwiki.php más el parámetro a ejecutar (cuando el usuario hace click en la opción/enlace correspondiente):

  • “Edit” -> “pmwiki.php?action=edit
  • “History” -> “pmwiki.php?action=diff
  • “Backlinks” -> “pmwiki.php?action=search&q=link={*$FullName}” (donde $FullName es una variable: el nombre de la página que estamos visualizando y sus páginas relacionadas -no existen jerarquías en PmWiki, solo existe en nuestros cerebros-)
PmWiki Site.PageActions
PmWiki Site.PageActions

Aquí es que vamos a llegar al meollo del asunto: dichas palabras “Edit”, “History” y “Backlinks” aparecen  en el código no como texto en sí, sino como “variables”: “$[Edit]”, “$[History]” y “$[Backlinks]” de manera tal que esas variables definidas se puedan especificar en un archivo con la extensión “.XLPage” con el siguiente contenido según nuestros ejemplos seleccionados:

  • ‘Edit’ => ‘Editar’
  • ‘History’ => ‘Historial’
  • ‘Backlinks’ => ‘Retroenlaces’

Resulta ser que para nosotros en supuesto “idioma español” nos asignaron dos letras “Es” de esta manera nuestro idioma vienen ser definidos los mensajes comunes en un archivo llamado “PmWikiEs.XLPage“. Pensamos que deberíamos diferenciarnos porque en España se hablan varioas idiomas: gallego, castellano, catalán, vasco y portugués… que está bien, Portugal se independizó y cogió otro rumbo y otro idioma pero forma parte de lo que los romanos al civilizar llamaron “Hipania” (perdón por la lección de historia, je, je, je). Somos de la idea de que deberíamos tener OTRAS letras como, se nos ocurre “cas” (ya “ca” está tomado por el idioma catalán) pero en fin, todos llevamos dentro nuestro pequeño “Don Quijote de la Mancha” y en cada molino vemos fieros gigantes ¡ja!

Traducción de las páginas en sí.

Al abrir la página principal de PmWiki sin haberla internacionalizado (a eso vamos) en el panel izquierdo (“slide panel”) aparecerá varias opciones -en inglés- de las cuales las tres primeras (hay site opciones en esa sección) dirán:

  • “Initial Setup Tasks”
  • “Basic Editing”
  • “Documentation Index”.

Si colocamos el puntero sobre ellas, sin hacer click, veremos que sus enlaces web (llamados a pmwiki.php acompañados de un parámetro) serán los siguientes -coloreamos para que veáis las diferencias, no colocamos el enlace completo porque cada dominio web es diferente-:

  • pmwiki.php?n=PmWiki.InitialSetupTasks
  • pmwiki.php?n=PmWiki.BasicEditing
  • pmwiki.php?n=PmWiki.DocumentationIndex

Lo coloreado en color marrón son “páginas del sistema” de PmWiki y son las que debemos traducir ¿recordáis las dos letras de código de nuestro idioma? Pues las debemos intercalar para que apunten a los archivos que vamos a descargar con las traducciones:

  • pmwiki.php?n=PmWikiEs.InitialSetupTasks
  • pmwiki.php?n=PmWikiEs.BasicEditing
  • pmwiki.php?n=PmWikiEs.DocumentationIndex

Del siguiente enlace podréis descargar los idiomas disponibles en incluso un “megapaquete” con todas las traducciones. Nosotros solo descargaremos el archivo “i18n-es.zip” el cual descomprimiremos y “subiremos” a nuestro servidor teniendo cuidado de darle los permisos de lectura necesarios y los ubicaremos todos en la carpeta wikilib.d

Activando el idioma deseado.

En este punto debemos editar de nuevo el dichoso fichero llamado “config.php” que está ubicado en la carpeta /local y modificar y adicionar las siguientes líneas:

include_once("scripts/xlpage-utf-8.php"); # optional
XLPage('es','PmWikiEs.XLPage');

La primera línea en realidad la descomentamos porque viene así de la plantilla por defecto, y ese comentario que indica “optional” osea opcional para nosotros es obligatorio (ya eso lo explicamos en nuestro tutorial HTML). La segunda línea indica el llamar a la función XLPage y tiene dos parámetros:

  • El primer parámetro son las letras que mostrará en el cintillo inferior en el caso que instalemos varios idiomas, no tiene nada que ver con la codificación ISO de dos letras. Por razones estéticas y debido a la cantidad de idiomas y que ninguno destque de los demás se escoge ese formato pero nada nos impide colocarle “español” o “castellano”; queda a vuestro criterio -si manejais pocos idiomas-.
  • El segundo parámetro es el nombre exacto del archivo porque los servidores GNU/Linux distinguen mayúsculas de minúsculas. Aquí queda de parte de nosotros mantener la clave ISO “Es” para claridad de nuestros archivos, debemos ser conscuentes en esto porque nuestros grupos de páginas llevarán siempre el perfijo PmWikiEs.

Mejorando la selección de idioma.

No sabemos quien visitará nuestra página en este mundo tan globalizado, pero si utilizan un navegador web que se haya programado según las normas del W3C lo mejor que podemos hacer es incluir en config.php el siguiente guion:

1
2
3
4
5
6
7
8
9
10
11
12
$lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
switch ($lang){
case "es":
XLPage('es','PmWikiEs.XLPage');
break;
case "en":
XLPage('en','PmWikiEn.XLPage');
break;
default:
XLPage('en','PmWikiEn.XLPage');
break;
}

En la primera línea por medio de PHP le preguntamos al servidor web el encabezado con que solicita la página nuestro visitante y extraemos las dos primeras letras para luego seleccionar de los idiomas disponibles que tengamos instalados, y por defecto, si no se consigue, pues lo mostramos en ingéls, el lenguaje “materno” de PmWiki. Lo hemos probado con Mozilla Firefox 53 y funciona.

Visualizando por primera vez nuestra página en nuestro idioma.

Pues tan simple como recargar la página y los mensajes comunes estarán en nuestro idioma… pero hasta allí llega nuestra “alegría de tísico” (por lo poco que dura antes de entrar en un atque de tos). Resulta que igual nos aparece en inglés todo lo demás y he aquí que debemos comenzar a trabajar.

PmWiki página principal por defecto -idioma español establecido-
PmWiki página principal por defecto -idioma español establecido-

La primera página que modificaremos es precisamente la principal llamada “Main.HomePage” la cual, por ahora, no hemos encontrado manera de cambiar al castellano. Lo que es cierto es que podemos -y debemos- modificarla borrando todo el contenido en inglés e ir creando nuestro propio contenido para luego modificar el panel izquierdo (“edit SideBar”).

Nuestro primer grupo de páginas.

Aunque suene extraño vamos a aventurarnos a crear dos grupos de páginas de una vez. Para ello ya estamos modificando la “Main.HomePage” (luego de haber introducido nuestra contraseñade edición, si la hubiéramos establecido) y escibiremos el siguiente código:

[[WikiAeroplanos | Aviones]]
* [[WikiAeroplanos.Cazas | Uso militar]]
* [[WikiAeroplanos.Pasajeros | Transporte]]
* [[WikiAeroplanos.Hidroaviones | Mixto]]

[[WikiTrenes | Trenes]]
* [[WikiTrenes.Electricos | Siglo XXI]]
* [[WikiTrenes.Vapor | Siglo XX]]

Le damos guardar y al recargar la ápgina veremos lo siguiente:

PmWiki creando grupos de páginas
PmWiki creando grupos de páginas

¿Observáis los signos de interrogación que nosotros no escribimos? Pues es la maner de PmWiki indicarnos que dicho tema no ha sido escrito. Aquí radica la sencillez y rapidez de PmWiki: cuando hacemos click se abre inmediatamente para editar cada una de las págins que queremos desarrollar. He aquí que le vamos agregar un poco de complejidad a cada una de ellas.

Fuentes consultadas.

En idioma francés.

En idioma inglés.

PHP tutorial

Un lenguaje importante y que hemos dejado de lado por años es el ya muy famoso lenguaje PHP. En desagravio publicamos esta entrada y le queremos dar características especiales: no insisteremos en ser detallistas al extremo, se trata de una introducción, un tutorial que lleve paso por paso a cualquier persona que desee aprender dicho lenguaje de programación. Por ello no publicaremos su historia, configuración del servidor, etcétera. Os recordamos que para aprender PHP sería bueno tener conocimientos mínimos de HTML, CSS y JavaScript.

PHP de manera “sucia y rápida”.

No nos asustéis con la traducción al castellano del popular refrán en idioma inglés “quick and dirty”, que siempre se recuerda cuando se necesita desarrollar algún software que goce de pragmatismo al extremo. Lo que queremos decir es que cuando uno necesita resultados rápidos pues conviene saltarse los “paso a paso” que siempre usamos para aprender algo nuevo.

Elementos básicos en PHP.

El lenguaje PHP bien puede utilizarse en comandos por una venta terminal o bien lo podemos usar un proceso por lotes almacenados en un archivo de texto al cual le colocaremos una extensión “.php” para identificar de manera rápida su contenido. Siendo entonces un fichero en texto plano procedemos a escribir dentro de él lo siguiente:

<?php
  // aquí va el código
?>

Estas tres simples líneas le indican al servidor dónde comienza y termina las instrucciones que va a ejecutar en lenguaje PHP. Esto es así porque dentro de un archivo “.html” podremos incluir código especial que muy probablemente emita código en lenguaje HTML de manera dinámica (por ejemplo, una consulta en una base de datos para mostrar los valores seleccionados por el usuario). Las dos barras inclinadas “//” indica que todo lo que está a la derecha y hasta el final de la línea son comentarios y que no deben ni serán ejecutados. Tambien sirve “#” para comentar una línea, pero si necesitamos comentar varias líneas escribimos “/* comentario(s) */“.

Con excepción de las líneas de comentarios, inicio y cierre, toda las demás líneas deben terminar con un punto y coma “;“.

Variables en PHP.

Toda variable comienza con “$” y un caracter A-Z (mayúsculas y/o minúsculas) y/o el guión bajo “_“, luego se pueden usar números y/o caracteres sin dejar espacios. Se pueden clasificar en:

  • Número entero (positivos o negativos).
  • Número flotante (número decimal positivos o negativos).
  • Booleano (verdadero o falso).
  • Cadena de caracteres (las almacenamos con comillas simples).

Hay cuatro tipos más de variables avanzadas que veremos en su debida oportunidad. Una vez hallamos guardado un valor en una variable se pueden mostrar por pantalla por medio de las ordenes echo o print(), las cuales tiene muchas opciones que veremos más adelante pero detallaremos que no es lo mismo usar comillas simples que dobles con dichas funciones, mirad este ejemplo:

<?php
  miValor = 5;
  echo '<p>El valor es $miValor .</p>';
  echo "<p>El valor es $miValor .</p>";
?>

Y devolverá lo siguiente (código HTML recibido por el navegador, en Mozilla Firefox pulsad las teclas CTRL+U):

<p>El valor es $miValor.</p><p>El valor es 5.</p>

Así vemos que el comando echo bien puede “pasarle” al navegar el texto (en este caso texto + lenguaje HTML) o bien puede mediante instrucciones especiales “pasar” el valor almacenado en una variable. Notad que aunque los comandos en PHP es indistinto si los escribimos en mayúsculas y/o minúsculas las variables son sensibles: no es lo mismo $miValor que $MiValor, mucho cuidado con eso que causa bastantes dolores de cabeza a nosotros los programadores.

Otro uso en el campor de las variables, aunque poco utilizado, es declarar una segunda variable por referencia con otra variable. Para esto usamos el caracter “&” justo delante de la variable que queremos pasar. Ejemplo:

$a = "texto"; $b = &$a; echo $b;

Suma de variables en PHP.

Para sumar dos variables, ya sea para presentarla por pantalla o para almacenarla en otra variable, utilizamos los operadores matemáticos de costumbre, mirad:

<?php
 $a = 5; $b = 10; $c = $a + $b;
 echo "a + b =";
 echo $a + $b;
 echo "<br>c=";
 echo $c;
?>

Concatenar variables en PHP.

Decimos concatenar en el caso de variables de texto, en PHP con un simple punto unimos la variables:

<?php
 $a = "Inicio"; $b = " fin.";
 echo $a.$b;
?>

Declaración y alcance de las variables en PHP.

Como estudiamos hace poco, no es necesario decirle a PHP qué tipo de variable vamos a trabajar, simplemente ponemos los valores y el lenguaje se encarga de almacenarlo en el lugar adecuado. Cuando vayamos a realizar operaciones con dichas variables éstas se convertirán de a un valor correcto, por ejemplo:

<?php
 $a = "palabra"; $b = 5;
 echo $a + $b;
 echo "<br>";
 echo $a.$b;
?>

El resultado por pantalla será “5”, es decir, el valor de $a es una cadena de texto cuyo valor numérico es cero y así lo convierte para sumarlo a $b. Por el contrario, en la siguiente línea $a.$b estamos concatenando cadenas de texto y el valor de $b se convierte en el caracter “5” para mostrar lo siguiente:

5
palabra5

En PHP podemos “forzar” que una variable sea de un tipo específico que necesitemos, para ello usar el comando settype() con dos argumentos entre paréntesis separado por una coma: nombre de la variable y luego el tipo de variable (“integer”, “double”, “string”, “booelan”), ejemplo: «setttype( $a , “integer”)».

Otra manera de forzar a un tipo de variable es de la siguiente manera: «$variable = (int) $variable;» en este caso (int) o (integer) indica que lo cambie a tipo entero pero podemos usar también (real), (double), (float), (boolean) o (bool).

Otra cosa es el alcance de las variables: si están en el módulo principal las variables serán globales y si están dentro de una función serán locales y solamente podrán ser accesibles dentro de la función donde fueron “creadas”. Si necesitamos que una variable dentro de una función esté disponible para otras funciones (y en el módulo principal) usaremos la palabra global y a continuación le asignaremos el valor; de facto estamos declarando la variable al asignarle un valor.

Cuando declaramos una variable como global ésta se adiciona a la matriz $GLOBALS[‘nombre_de_variable’] y podemos acceder a ellas de esta manera nemotécnica, especialmente es útil para usarla dentro de funciones; ejemplo: «echo $GLOBAL[‘cadena’]». Aunque aún falta mucho para ver las funciones, podemos adelantar el siguiente código que ilustra el alcance de las variables locales y globales:

<?php
 $variable1 = 'ABC';
 $variable2 = 123;
 function mi_funcion(){
  $variable1='perro';
  echo $variable1.'<br>';
  echo $GLOBALS["variable1"].'<br>';
  echo $GLOBALS["variable2"].'<br>';
 }
 mi_funcion();
?>

Si necesitamos que una variable dentro de una función conserve su valor entre llamadas, debemos declararla con el comando static dentro de la función a la que pertenece y asignarle un valor, por supuesto.

Incrementos y decrementos en variable numéricas.

Como es popular en lenguaje C++ los incrementos se logran colocándole “++” (o “–” si es un decremento) luego del nombre de la variable. En este ejemplo ambas líneas son equivalentes pero en una escribimos más que en la otra:

<?php
 $a = 10;
 $a = 10 + 1;
 echo $a."<br>";

 $a = 10;
 $a++;
 echo $a."<br>";
?>

Pero fijaos que al mostrarlo en pantalla, cuando el incremento (o decremento) lo colocamos ANTES o DESPUÉS de la variable se comporta de manera diferente, cambia el orden de como se ejecutan las instrucciones:

<?php
 $a = 10;
 echo "Incremento posterior:<br>";
 echo $a++."<br>";
 echo $a."<br>";
$a = 10;
 echo "Incremento anterior:<br>";
 echo ++$a."<br>";
 echo $a."<br>";
?>

Operaciones artiméticas en PHP.

Aparte de las cuatro operaciones básicas (suma “+”, resta “-“, multiplicación “*” y división “/”) debemos señalar también al módulo “%” (devuelve el residuo de la división, si es cero la división es exacta) y la exponenciación “**”.

Otros operadores importantes son la suma y asignación “+=”, resta y asignación “-=”, multiplicación y asignación “*=”, división y asignación “/=”, módulo y asignación “%=” y concatenación y asignación “.=”. Esencialmente lo que hace es aplicar el operador aritmético al valor ya almacenado en la variable con el otro valor a la derecha del signo de igualdad. El siguiente código ilustrará mejor:

<?php
 $x=10;$x+=5;echo $x."<br>"; # resultado 15
 $x=10;$x-=5;echo $x."<br>"; # resultado 5
 $x=10;$x*=5;echo $x."<br>"; # resultado 50
 $x=10;$x/=5;echo $x."<br>"; # resultado 2
 $x=10;$x%=5;echo $x."<br>"; # resultado 0
?>

Operadores de comparación.

Necesitamos oepradores que permitan comparar dos variables, pero en PHP hay ciertas condiciones a evaluar. Para empezar ya sabemos que las variables puede almacenar valor numérico y en la siguiente línea le podemos almacenar una cadena de texto, es por ello que necesitamos comparar, incluso, si son el mismo tipo de variable. Por ejemplo, para nosotros 5 es igual que 5,00 paro para PHP el primer valor es un número entero positivo y el segundo es un valor decimal positivo (nosotros en este sitio web nuestro separador decimal es la coma pero a nivel de lenguajes de computación el separador decimal es el punto). Veamos los que disponemos:

  • ==“: Comprueba si son iguales.
  • !=“: Comprueba si son distintos.
  • ===“: Comprueba si son iguales y de exactamente el mismo tipo.
  • !==: Comprueba si son distintos o de distinto tipo.
  • <>: Diferente (igual que !=).
  • <: Menor que, comprueba si un valor es menor que otro.
  • >: Mayor que.
  • <=: Menor o igual que.
  • >=: Mayor o igual que.
  • <=>: Comparador de orden (PHP 7).
  • ??: uno o el otro (PHP 7).

Trabajando con variables de texto.

PHP contiene comandos (funciones no declaradas por nosotros, funciones implícitas) que nos facilitan grandemente nuestro trabajo con cadenas de texto, ya vimos echo y print() veamos otras más.

Contando el número de caracteres.

Usaremos el comando strlen() pasando como argumento nuestra variable (osea colocamos nuestra variable dentro de los paréntesis del comando). Por ejemplo, el siguiente código devolverá el valor de treinta y cinco letras:

<?php
  $cadena = "República Bolivariana de Venezuela";
  echo strlen($cadena);
?>

Pero el problema aquí es que no son 35 caracteres sino 34: la letra u acentuado es contada como 2 caracteres porque se necesitan 2 bytes para representarla. En realidad esta función devuelve el número de bytes, no el número de caracteres. Ya vemos que nuestro hermoso idioma castellano, normado por nuestro brillante Don Andrés Bello, nos da y seguirá dando trabajo a nosotros los programadores.

Contando el número de palabras en una cadena de texto.

Teniendo en cuenta que una palabra esta delimitada antes y después por uno o más espacios y esté constituida por caracteres A~Z y/o a~z, el comando que usaremos es str_word_count(). Siguiendo con el ejemplo anterior:

<?php
  $cadena = "República Bolivariana de Venezuela";
  echo str_word_count($cadena);
?>

Y el resultado será simplemente cinco ¿Qué sucedió si sólo hay cuatro palabras? Pues lo mismo de siempre: los lenguajes de programación están escritos por gente de habla inglesa para los cuales los acentos, la letra eñe -y demás caracteres no pertenecientes al idioma inglés simplemente no existen. Pero esperen, aún hay más: los números tampoco cuentan como caracteres así que por lo menos no nos podemos quejar de que ellos allá en el departamente de programación de PHP no son estrictos con ellos mismos. Veremos de forma ampliada que este comando acepta un segundo parámetro llamado format que permite el resutlado de manera distinta: si es cero es el valor por defecto, uno devuelve una matriz conteniendo cada una de las palabras y dos devuelve la posición numérica de cada una de las palabras, veamos:

<?php

  $cadena = "República      Bolivariana
       de     Venezuela";
  echo "<br>Palabras encontradas:";
  echo str_word_count($cadena);
  echo "<br><br>Valor FORMAT por defecto cero:<br>";
  print_r(str_word_count($cadena, 0));
  echo "<br><br>Matriz con cada una de las palabras:<br>";
  print_r(str_word_count($cadena, 1));
  echo "<br><br>Matriz con la ubicación de cada una de las palabras:<br>";
  print_r(str_word_count($cadena, 2));

?>

Lo cual devuelve lo siguiente:

Palabras encontradas:5

Valor FORMAT por defecto cero:
5

Matriz con cada una de las palabras:
Array ( [0] => Rep [1] => blica [2] => Bolivariana [3] => de [4] => Venezuela ) 

Matriz con la ubicación de cada una de las palabras:
Array ( [0] => Rep [5] => blica [16] => Bolivariana [35] => de [42] => Venezuela )

Fijaos que la cadena de texto hemos introducido más espacios adicionales, la hemos escrito en dos líneas pero PHP la interpreta como una sola ya que al final de la segunda línea es que se encuentra el punto y coma que indica el final. También ya sabéis que la letra u acentuada cuenta como dos caracteres (ya que esa característica del juego de caracteres UTF-8 permite “ampliar” el número de bytes para representar los más de 65 mil caracteres que componen el UNICODE) y es por ello que “blica” comienza en 5 y no en 4.

Pensando ellos allá en lo anterior, a partir de la versión PHP 5.1.0 se le agregó un tercer argumento que permite especificar una excepción a los caracteres que nosotros consideramos no delimita una palabra. Esto conlleva definir un valor constante a lo largo de todo nuestro programa por medio del comando define() que toma dos argumentos separados por una coma: primero el nombre de la variable en sí y segundo el conjunto de caracteres que consideramos NO delimita una palabra y encerrados entre comillas, mirad el siguiente ejemplo:

<?php

  define( Castellano, 'áéíóúÁÉÍÓÚüÜñÑ');

  $cadena = "República Bolivariana de Venezuela.
En Güigüe se siembra mucho el ñame y el limón.";
  echo "<br><br>Valor FORMAT por defecto cero:<br>";
  print_r(str_word_count($cadena, 0, Castellano));
  echo "<br><br>Matriz con cada una de las palabras:<br>";
  print_r(str_word_count($cadena, 1, Castellano));
  echo "<br><br>Matriz con la ubicación de cada una de las palabras:<br>";
  print_r(str_word_count($cadena, 2, Castellano));

?>

Importante hacer notar que los valores constantes NO necesitan el signo “$” delante: ya PHP sabe que es un valor “especial” a tomar en cuenta. La función include() acepta un tercer parámetro: podemos especificar que el nombre de la variable NO sea sensible a mayúsculas y minúsculas. Esto quiere decir que si colocamos true en el tercer argumento, podremos llamara a nuestra constante a lo largo del programa como “Castellano” o “CASTELLANO” o “cASTELLano”, etc. Toda constante declarada es de tipo GLOBAL. A partir de PHP 7 acepta valores de matrices, solo como nota informativa.

Cadenas reversadas.

Si queremos encontrar palíndromos esta función está adecuada para ello: strrev() devuelve una cadena de texto al revés, un ejemplo en idioma latín:

<?php
 // Latín: "Damos vueltas en la noche y somos consumidos por el fuego"
 echo "in girum imus nocte et consumimur igni<br>";
 echo strrev("in girum imus nocte et consumimur igni");
?>

Encontrar una subcadena en una cadena de texto.

Función bastante usada: necesitamos saber si en una cadena de texto existe una subcadena: strpos() devolverá un valor numérico, cero o mayor si consigue la subcadena, de lo contrario devolverá un valor falso. Debemos tener en cuenta que falso=cero y cualquier otro valor es verdadero, como esta función puede devolver cualquier valor entonces debemos evaluar con el triple signo de igualdad para estar seguros que no se consiguió la subcadena. Ejemplo:

<?php
 $cad=strpos("Ministerio del Poder Popular para la Comunicación e Información.", "Comunicación"); //
 if ($cad===false){
 echo "falso";
 }else{
 echo $cad;
 }
?>

Sustituir una subcadena de texto.

Dada una cadena de texto necesitamos sustituir, si se consigue dentro de ésta, por otra cadena de texto: str_replace() hará el trabajo si le colocamos como primer argumento la subcadena a buscar, el segundoa rgumento la cadena que sustituirá -de ser encontrada- y la cadena de texto en donde se buscará. Ejemplo:

<?php
 $cad=str_replace("Sulia", "Zulia", "Maracaibo, estado Sulia.");
 echo $cad;
?>

Extraer una subcadena de texto.

Muchas veces necesitamos extraer un subcadena de texto a partir de su posición numérica hasta el fin de la cadena de texto: substr() con tres argumentos: cadena de texto, comienzo y longitud. Si se omite la longitud pues devolverá hasta el final de la cadena de texto. Si el número de comienzo es negativo devolverá la cadena contando como primer caracter el primero de la derecha, osea el final. Si no consigue la cadena devolverá un valor falso o una cadena de texto vacía.

<?php
 # Muestra "para no serlo"
 echo substr("Llamarse jefe para no serlo es el colmo de las desgracias.",14,13);
?>

Instrucciones condicionales.

Si condicional.

Para evaluar una variable y un valor o dos variables (o dos valores, algo menos común) usaremos el si condicional. En PHP tiene la siguiente estructura:

if (condición a evaluar) {instrucciones a ejecutar}

if (condición a evaluar) {
  instrucciones a ejecutar;
}

De la segunda manera resulta más ordenada y estructurada pues permite multilíneas comodamente. Si necesitamos ejecutar instrucciones diferentes según la condición verdadera o falsa:

if (condición a evaluar) {
  instrucciones a ejecutar;
} else {
  instrucciones a ejecutar;
}

Lo coloreado en verde se ejecuta si la condición es verdadera y lo coloreada en morado de ser falso. Cuando necesitamos evaluar varias condiciones, “filtro de múltiples tamices” utilizaremos esta estructura:

if (condición a evaluar) {
  instrucciones a ejecutar;
} elseif (condición a evaluar) {
 instrucciones a ejecutar;
} else {
 instrucciones a ejecutar;
}

Con el siguiente ejemplo ilustraremos mejor la estructura: con la función date() obtenemos la hora y fecha del equipo pero si le pasamos la máscara “H” nos devuelve solamente la parte de la hora y en formato militar (hora de 24 horas); se pasa por un tamiz dicho resultado y según la hora saluda de manera adecuada:

<?php
  $hora = date("H");
  if ($hora < "12") {
   echo "Buenos días.";
 } elseif ($hora < "19") {
   echo "Buenas tardes.";
 } else {
   echo "Buenas noches.";
 }
?>

Como vemos con tres condiciones revista ya cierta complejidad por lo que es necesario un operador más poderoso: el comando switch().

Interruptores condicionales.

Acá debemos abrir un poco la mente: muchas veces necesitamos comparar una variable contra diferentes valores para ejecutar una o más instrucciones e incluso necesitamos que dicha variable sea evaluada más de una vez. Para ello existe el comando switch() que evalua exactamente cada valor y si coincide exactamente ejecuta la(s) instrucción(es) y sale del ciclo con un comando break():

<?php
$i=0;
switch ($i) {
    case 0:
        echo "i vale 0<br>"; break;
    case 1:
        echo "i vale 1<br>"; break;
    case 2:
        echo "i vale 2<br>"; break;
    default:
      echo "i es mayor a 2<br>";
}
?>

El ejemplo se establece el valor en cero y solo se ejecuta la primera instrucción y sale del ciclo. Cualquier valor que NO sea 0, 1 ó 2 imprimirá “que i es mayor a 2” incluso si $i tiene un valor negativ0. Es por ello que este comando debe ser ejecutado con precaución. Otro detalle a tomar en cuenta es que si queremos ejecutar varia líneas de instrucciones debemos encerrarlos entre corchetes.

Comandos de ciclo.

Ciclo mientras “while”.

Con el ciclo while() si se cumple la condición evaluada se ejecutarán una y otra vez cada una de las instrucciones contenidas y se espera que dentro del ciclo hayan eventos que cambien el valor y poder salir del bucle, sino decimos que el ordenador “está colgado”, así que mucho cuidado con esto último:

while (condición evaluada) {
     instrucciones a ser ejecutados;
 }

Como ejemplo utilizaremos la variable k con un valor inicial de 1 y lo incrementaremos de dos en dos hasta que supere a diez:

<?php
  $k = 1;

  while($k < 10) {
    echo "Valor de <i>k</i>: $k <br>";
    $k += 2;
}
?>

Ciclo hacer mientras “do … while”.

El ciclo mientras “while” evalúa la condición y de ser cierta ejecuta el bloque de instrucciones deseado en cambio el ciclo hacer-mientras entra al ciclo, ejecuta y luego evalúa la condición: si se cumple vuelve a ejecutar de lo contrario sale del ciclo y continúa el flujo del programa. Para ilustrar bien este punto colocamos el siguiente ejemplo muy a propósito para demostrarlo:

<?php
  $k = 10;
  do {
    echo "The number is: $x <br>";
    $k++;
  } while ($k <= 5);
?>

Este código mostrará “El valor de k es: 10″ que sabemos que es mayor que 5 sin embargo el bloque de instrucciones se ejecuta al menos en una oportunidad.

Ciclo para “for”.

El anterior hacer-mientras se hace más fácil de ejecutar con el ciclo para el cual tiene tres parámetros: el que inicializa la variable, la condición que evalua la variable y el incremento en cada ciclo que le vamos a aplicar a la variable:

for (inicia_contador; evalua-contador; incrementa_contador) {
  código_a_ejecutar;
}

Con valores numéricos puede ser más “fácil” de comprender:

<?php
  For ($fuente=1; $fuente<=7;$fuente++) {
    echo "<font size=$fuente>Tamaño de fuente $fuente</font><br>";
  }
?>

Ciclo para cada “for each”.

Este comando se utiliza con matrices, se estudiará más adelante cuando veamos este tipo de objetos.

Funciones personalizadas.

Ya tocamos el tema de bastantes “comandos” o funciones implícitas en PHP: no es necesario declararlas, ya están implementadas y aunque podemos hacer bastante con el trabajo hecho de manera previa esto no es suficiente para desarrollar nuestros programas. Por esta razón PHP (y la mayoría de los lenguajes de programación) permiten hacer nuestras propias funciones, aquellas que esperamos usar de manera repetitiva en nuestros programas.

function nombre_de_funcion(argumento) {
}

Las funciones NO son sensibles a minúsculas y/o mayúsculas: no importa como la escribamos ellas son llamadas y ejecutadas. Con valores:

<?php
  function muestra_mensaje() {
    echo "Ejemplo de funciones de PHP.";
  }

Muestra_Mensaje(); // Hace el llamado a la función.
?>

Acá comprobamos que no importa como llamemos la función, ésta es ejecutada. Por ahora a esta función no le pasamos ningún argumento pero a continuación la modificamos y dentro de ella con el valor que le pasamos podemos trabajar y procesarlo para mostrarlo o devolver algún resultado en memoria:

<?php
  function muestra_mensaje($mensaje) {
    echo "Ejemplo de funciones de PHP.<br>";
    echo $mensaje;
  }
Muestra_Mensaje("¡Aprendiendo a programar en PHP!"); 
?>

También podemos pasar un argumento con un valor por defecto, dado el caso no le pasemos un valor:

<?php
  function muestra_mensaje($mensaje = "Ejemplo de funciones de PHP.<br>") {
    echo $mensaje;
  }
Muestra_Mensaje();
Muestra_Mensaje("¡Aprendiendo a programar en PHP!");
?>

Por último con la orden return variable podremos beneficiarnos del uso más poderoso de las funciones: devolver valores:

<?php
  function suma($a, $b) {
    $total = $a + $b;
    return $total;
  }

echo "5 + 10 = " . suma(5, 10) . "<br>";
echo "7 + 13 = " . suma(7, 13) . "<br>";
echo "21 + 4 = " . suma(21, 4);
?>

Fuentes consultadas.

En idioma inglés:

¿Cómo funciona Mozilla Firefox? Motor Gecko y el Proyecto Quantum

Interesante es saber sobre cómo funciona el navegador web Mozilla Firefox (para nosotros, nuestro favorito) y vamos a diseccionar y explicar de manera sencilla, sin mayores pretensiones, sus diversos componentes. Para ello comenzaremos de atrás para adelante: el último Proyecto de Mozilla Firefox llamado “Quantum“, ¡Investiguemos juntos!

Introducción.

Quantum” es, como dijimos, el último proyecto que hace de Mozilla Firefox 53 una versión destacada sobre las anteriores. Tan grande es el proyecto que hubo la necesidad de ir abonando el camino para ello con el Proyecto “Electrolysis” apuntando así a un objetivo más alto. Nosotros, por estos lares, hemos seguido de cerca la evolución de los procesadores de 32 bits a 64 bits y ha sido nuestro mayor “trauma” a la hora de programar y compilar en diferentes ambientes. Pero he aquí que en los programadores de Mozilla están más bien preocupados por los dispositivos con múltiples procesadores y, de paso, en diferentes hardwares (ordenadores de mesa, dispositivos portátiles, móviles celulares y paren ustedes de contar).

Ellos primero están apostando a los procesos paralelos: cada pestaña o ventana es un hilo de programación y si colapsa solo reiniciamos el que falló, no todo el proceso principal de Firefox. Por supuesto, no solo esto lo han mejorado, nosotros por acá hemos explicado la novedosa Norma de Diseño de Cuadrícula sin contar que incluyeron temas “compactos”, nuevas extensiones para el navegador, “máscaras” de CSS, mejor experiencia con archivos multimedia, y los usuarios en Microsoft Windows pueden seleccionar si instalan la versión de 32 ó 64 bits.

Componentes principales de Gecko.

Para finalizar con la introducción diremos que muchos de los componentes del proyecto “Quantum” están desarrollados en lenguaje Rust, solo por mencionar ya que no profundizaremos en el asunto (abajo están los enlaces si queréis ir más lejos). Los componentes a la fecha son los siguientes:

  • rust-bindgen: es el “conector” entre el lenguaje C++ {con el que está(ba) escrito el código de Firefox} y el lenguaje Rust.
  • Quantum CSS ‘Stylo’: maneja las Hojas de Estilo en Cascada pero de manera “paralela”.
  • Quantum Render: se encarga de “dibujar” en pantalla.
  • Quantum DOM: se encarga de estructurar el archivo recibido en HTML.
  • Quantum Flow: para analizar el rendimiento y para mejorar la aplicación.

Más adelante explicaremos los componentes considerados básicos, mantendremos al mínimo este tutorial.

Nociones básicas.

Un navegador web es un software que lee un archivo escrito en lenguaje HTML y lo interpreta según normas recomendadas y preestablecidas para mostrarlo a nosotros de una manera interactiva. Dicho archivo reposa en un servidor web y asumiremos que simplemente es un fichero que reposa en dicho sitio -esto no es rigurosamente cierto ya que hoy en día las págnas web son dinámicas, es decir se presentan de diferentes maneras según el navegador, usuario, datos solicitados e incluso según la ubicación y dispositivo-.

Decimos que un navegador web tiene un motor web (“browser engine”) y en el caso de Firefox este motor es llamado Gecko el cual tiene muchos componentes de lo cuales nombramos algunos en la introducción.

Aclaratoria necesaria.

Todo lo que aquí presentamos es cierto para la versión Firefox 53 el cual esperamos tengáis instalado ya que hay varios elementos gráficos que solo se mostrarán correctamente en esa versión (o superior).

Simplificando al máximo.

Haciendo un panorama general, toda página web se puede dividir en tres partes principales:

Documento HTML (estructura).

Como establecimos y es un hecho cierto al nosotros ejecutar cualquier navegador web y solicitar en la barra de direcciones un dominio cualquiera lo que recibimos es simplemente un fichero con instrucciones en HTML. Un vez recibido es cuando realmente comienza el proceso de leer, analizar e interpretar dicho código. En inglés a esta pieza de software le llaman parser por su derivación del idioma latín “pars orationis” (parte del discurso, estructura gramatical) y que ellos simplemente abrevian pars, lo toman como si fuera un verbo y lo convierten en sustantivo agregandole el sufijo “er”: es así que tenemos el parser y que nosotros lo llamaremos analizador (ya la web abunda en inglés, debemos construirla también en castellano ¡ayúdanos siguiendo el ejemplo!).

Modelo de Objeto Documento («Document Object Model ‘DOM’»).

Acá es donde interviene el primer analizador: se encarga de categorizar y formar un árbol a partir de las etiquetas claves en HTML: head, body, div, footer y va más allá con cada uno de los párrafos, titulares, etiquetas personalizadas, etc. de cada sección. Lo más importante es que forma un índice de elementos a modo de catálogo para que cuando sea consultado por medio de otros componentes pueda ser retribuido rápidamente. Recordad también que debido al JavaScript dicho DOM puede ser modificado posteriormente y debe ser capaz de registrar y llevar control de dichos cambios.

Nosotros vemos al DOM como una especie de base de datos donde almacenamos el código HTML de una manera normalizada.

Hojas de Estilo en Cascada («Cascading Style Sheets ‘CSS’»).

Ahora tenemos otro analizador: el que se encarga de darle formato al código HTML que está categorizado en el DOM. En teoría cada elemento en el CSS debería tener su correspondiente en el DOM. De igual manera este analizador se encarga de categorizar de manera sucesiva los estilos que estén en el fichero -o sección- CSS. Decimos de manera sucesiva porque tal vez se nombre varias veces al mismo elemento HTML y el último en ser leído será el estilo como será presentado (esto no sucede a menudo por ser un desperdicio de trabajo redundar en el estilizado de componentes). Este último resultado es el que se va a proceder a enviar al motor de diseño.

Motor de Diseño («Layout»).

Ya con el estilo aplicado cada uno de los componentes son preparados para ser dibujados y dejarlo listo en capas para pasarlo al siguiente paso.

Motor de Capas

Recibe las capas y las lleva en orden de jerarquía según se haya determinado y las mantiene ordenadas y listas para ser presentadas al motor de dibujo.

Motor de Dibujo.

Acá se coordina todo dejando los espacios necesarios entre cada capa (que se superpone y que se puede ver y que se oculta) además de estar pendiente de las posibles modificaciones a futuro producidas por el JavaScript.

Motor “Compositor”.

Recibe y abre en procesos paralelos cada página web que visualize el usuario, ya sea en una pestaña o una ventana nueva y si esto falla por alguna razón pues entonces vuelve a abrir otro proceso solicitando de nuevo al motor de dibujo que se mantiene incólume corriendo en un proceso aparte.

Motor de JavaScript.

Acá se establecen los eventos que disparará el usuario y que podrá modificar tanto como el HTML, el CSS o ambos al mismo tiempo (la mayoría de las veces el proceso no es tan “traumático”, podría ser simplemente mostrar un texto distinto lo cual es algo más sencillo de realizar por parte del sistema operativo que por la maquinaría de Firefox en sí).

Conclusiones.

Fuentes consultadas:

En idioma inglés:

En idioma italiano:

Python logo sin texto

Python http.server

La verdad es que revisando los temas publicados por nuestros colegas de GNULinuxBlog (por ahora quien publica el tema, el sr. Elías Rodríguez Martín y el sr. José Miguel, creador del blog) encontramos uno en particular muy útil y que nosotros habíamos enfocado de una manera un tanto complicada en comparación con la facilidad de lo que allí proponen. Cuando conseguimos que alguien es más listo que nosotros inmediatamente lo reconocemos y aprendemos de dichas personas, no tenemos rubor en admitirlo, por eso os pedimos que nos acompañéis en nuestro artículo de hoy: compartir ficheros de una manera rápida y sencilla con Python.

Python logo original
Python logo original

Introducción.

Pasar ficheros de una máquina a otra en algún momento nos tocó o tocará hacerlo y en nuestro caso fue de una máquina con Ubuntu hacia otra con software privativo ubicada fuera de nuestra red de área local. Para ello habilitamos un servidor FTP, en este caso ProFTPd, que conecta con las credenciales de otro usuario creado de manera exprofeso y con derechos de lectura sobre los archivos en cuestión. Eso a nosotros nos pareció fácil, pero ¿qué tal hacer algo que se pueda ejecutar en varios sistemas operativos?

Para ello nada mejor que Python: es legendario y ya en 1996 corría en sistemas tan diverso como Linux, IRIX, Compaq Tru64, OS X, Solaris, and Windows (ver caso de éxito “Industrial Light & Magic”, “Lucas Films LTD”). Al momento de escribir estas líneas Python (que ya va por la versión 3.6.1) está disponible para ser descargado y usado en Linux/Unix, Windows, AS/400 (OS/400), Beos, MorphOS, MS-DOS (sí, así como lo leen, no ha muerto, aún), OS/2, OS/390 and z/OS, RIC-OS, Symbian OS series 60, VMS, ¡¡¡ Windows CE or Pocket PC !!!, HP-UX y hasta podemos comprar una versión privativa a la cual no podremos acceder a su código fuente, y cuya distribución es llamada ActivePython (sabrá Dios en cuales plataformas de hardware ejecutará este último “sabor”) pero como véis, de que tenemos opciones y libertad de escoger es indudable, y si nos proponemos hasta podemos nosotros mismos hacer nuestra propia distribución de Python por nosotros elaborada (palabras mayores). Esto último es conocido como “implementaciones” y las podéis conocer más en este enlace -en idioma inglés-; ya por último debemos recalcar que Python es aceptado como lenguaje dentro del manejador de base de datos PostgreSQL ¡¿maravilloso, cierto?! 😎 .

Versión Python 2.x

En dicha versión 2.x se utiliza “SimpleHTTPServer” y lo probamos y comprobamos desde nuestra red de área local y desde una máquina externa, ya en la entrada que nos inspiró bien lo explican: solo debemos lanzar el siguiente comando (las librerías vienen integradas en Python):

python -m SimpleHTTPServer 8000

¿Fácil cierto? Nos vamos en una ventana terminal hasta la carpeta que contiene los archivos “a compartir”, lanzamos el guión en Python indicandole que abrimos el puerto 8000 y en el otro ordenador lanzamos nuestro navegador web con la dirección IP destino (si tenemos un enrutador pues configurad ALGO parecido a lo nuestro):

TP-LINK Forwarding Virtual Servers
TP-LINK Forwarding Virtual Servers

Reconocimiento a la labor del sr. Elías.

En su repositorio de aplicaciones -gentilmente alojadas por GitHub.com- el sr. Elías nos enseña como agregar valor al código existente por medio de una bonita interfaz gráfica para escoger la carpeta a compartir y cambiar el puerto de escucha -vamos que antes igual teníamos esa opción por la línea de comandos- pero con otro botón adicional: el botón de detener el servicio ya que por línea de comandos solo con CTRL+C se detenía el proceso. En la siguiente imagen comparto una carpeta de respaldo de un antiguo aparatito reproductos de MP3 y disfruto de música que tenía tiempo que no escuchaba:

PyShare (guion escrito por Elías Rodríguez Martín)
PyShare (guion escrito por Elías Rodríguez Martín)

Lo bonito del asunto del asunto (el guion, no la utilería gráfica PyShare) es que podemos navegar en nuestras carpetas, iniciar el servicio, detenerlo, ir a otra carpeta y repetir el proceso; y por si queda alguna duda sobre su funcionamiento se abre de una vez una pestaña en nuestro navegador web predeterminado para visualizar la carpeta compartida, todo muy práctico:

python_easy_server.py
python_easy_server.py

Lo que véis en la última imagen es el guión desarrollado por el Sr. Elías y el último error es simplemente un mal manejo de los caracteres de nuestro bello idioma castellano (compartí la carpeta llamada “Vídeos” que tiene un acento). Alegremente lo primero que hisimo fue lo que hacen los niñatos y niñatas de los parvularios, COPIAR Y PEGAR en un archivo llamado “python_easy_server.py” pero obviando la regla de oro: UTILIZAR GIT PARA CONTROLAR (y colaborar) EN EL CONTROL DE VERSIONES (mirad nuestro humilde tutorial al respecto).

No os vamos a “aburrir” con el tema de GitHub pero si os indicamos que propusimos unos cambios (“fork” y “pull request”) que podréis analizar con detalle en nuestros repositorios alojados -de nuevo, la publicidad- en GitHub.

Versión Python 3.X

Como bien especifica el sr. Elías en Python versión 3.x el SimpleHTTPServer ha sido sustituido por http.server y en esencia tiene la misma línea de comandos pero si analizamos el código pues bueno, todo de acuerdo a la nueva versión (3.6 en este caso). En el repositorio correspondiente en el módulo server.py leemos 1211 líneas y está muy bien explicado, un trabajo muy compacto con las deficiones básicas del protocolo HTTP y sobre cómo funciona por defecto esta librería escrita en Python.

Nos agrada mucho que vayan directo y al grano explicando cómo funciona un servidor web, eso es poesía informática, para muestra un botón: el inicio de la clase BaseHTTPRequestHandler:

The following explanation of HTTP serves to guide you through the
code as well as to expose any misunderstandings I may have about
HTTP (so you don’t need to read the code to figure out I’m wrong
:-).

Que traducido lo exponemos de la siguiente manera:

La siguiente explicación de HTTP sirve para guiarlo a través del código, así como para exponer cualquier malentendido que yo pueda tener sobre HTTP (por lo que no necesita leer el código para averiguar que estoy equivocado).

Allí se fajan a explicar cómo un servidor web recibe una petición y como se contesta, ya sea con el protocolo “HTTP/0.9” (por defecto en este módulo, línea N° 261), “HTTP/1.0” o “HTTP/1.1”. Esencialmente funciona de la siguiente manera (vamos a ser redundantes con propósitos didácticos):

  1. Un servidor web está funcionando con un “socket” abierto que se interpreta (y nos abstraemos) como un puerto abierto en un número conocido (por defecto es el puerto 80 pero como estamos usando algo “privado” usamos el puerto 8000).
  2. Un programa cliente, ya sea en nuestra propia red de área local o desde el internet, envía una petición a ese puerto conociendo de antemano la dirección IP del servidor web (no ahondaremos en el tema de los DNS, para los lectores más avezados).
  3. Esa petición tiene un protocolo específico: ejemplo “GET / HTTP/1.1″ ¿Pero que significa esto? Veamos el siguiente punto no sin antes mencionar que una petición puede contener dos líneas adicionales que son opcionales (por ahora no complicaremos la labor).
  4. Ante una petición tipo GET (en este caso nos exigen usar un protocolo específico HTTP/1.1) el servidor web procede a revisar el directorio por defecto (estamos hablando del http.server de Python, un servidor Apache es mucho más avanzado) y si encuentra un archivo index.html lo enviará, de lo contrario, si no lo halla entonces procederá a mostrar un listado de los archivos presentes en la carpeta desde donde ejecutamos el comando “python -m http.server 8000 (de hecho así también se comporta un servidor web Apache). Este último comportamiento lo podemos detallar en la función send_head() de la clase SimpleHTTPRequestHandler. Incluso podríamos aquí empoderarnos de nuestro idioma e incluir comandos para buscar también un archivo llamado “índice.html“, es decir, que ‘busque’ en inglés y castellano ¿Por qué no? (amén de traducir al castellano todos los demás mensajes). Así mismo, con acentos y todo el hecho de nosotros hablar dos o más idiomas ejercita nuestro cerebro, ampliamos nuestra memoria y nos ayuda a crear sinapsis nuevas en nuestras neuronas.
  5. La manera como envía esta respuesta debe estar ajustada al protocolo en el cual nos lo solicitaron. Para este ejemplo debemos contestar según el protocolo que nos pidieron [más abajo veremos que esto no es necesariamente cierto;-) ] y el cual consta de tres partes.
  6. La primera parte es una línea que está compuesta a su vez en tres segmentos:
    • Versión en la que estamos respondiendo (este ejemplo “HTTP/1.0“) más un espacio como separador al final.
    • Un código numérico de tres dígitos que está bien normalizado ( ¡A que alguna vez habrán visto una respuesta “404“! ). Para este ejercicio contestaremos con un “200” (más el consabido espacio en blanco como separador).
    • Un tercer segmento que explica ¡cómo no, en inglés! un mensaje descriptivo para nosotros los seres humanos (el código anterior, numérico, es muy agradable a nuestros amigos los ordenadores). El código 200 tiene la descripción simple y llana: OK.
  7. Para separar la primera parte de la segunda se recomienda utilizar la combinación de caracteres especiales de retorno de carro y avance de línea, pero debemos estar prestos a utilizar solo el avance de línea para una compatibilidad más amplia (de nuevo, ver BaseHTTPRequestHandler).
  8. La segunda parte son varias líneas llamadas encabezados y ajustados a la norma RFC-822 (la norma data del año 1982 pero pensamos está plenamente vigente).
  9. Un punto muy especial es que para separar la segunda parte de la tercera, además de utilizar el CRLF -ver punto 7- debemos insertar una línea en blanco, ¿cómo se hace esto? Pro favor ver la función end_headers() {línea 516} y os sorprenderéis.
  10. La tercera parte son los preciados datos en sí mismos cuyas características están especificadas de antemano en la segunda parte (recordad RFC-822).

Todo esto QUE PARECE COMPLICADO EN TEORÍA os lo podemos demostrar en la práctica: abrimos una ventana terminal y ejecutamos el servidor web Python, abrimos una segunda ventana terminal y ejecutamos la siguiente orden con el parámetro -i (o la manera larga –include) el cual muestra los encabezados HTTP:

curl -i http://192.168.1.47:8000/

Tras lo cual recibiremos la siguiente respuesta:

HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.5.2
Date: Sun, 16 Apr 2017 01:24:24 GMT
Content-type: text/html; charset=utf-8
Content-Length: 1370

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
(...

Acá la “magia” la realiza nuestro navegador web: según el Content-type se prestará a interpretar y mostrar de manera correcta los datos recibidos. Si es “text/html” pues vemos que es el lenguaje de marcado muy famoso y que además debemos mostrarlo con codificación utf-8. ¿Estáis confundido o perdido? Consultad nuestro tutorial sobre HTML.

Notad la respuesta del servidor identificandose a sí mismo “SimpleHTTP/0.6 Python/3.5.2“, maravilloso para nosotros. Mirad en la siguiente figura a lo que nos referimos:

Orden «GET HTTP 1.1»
Orden «GET HTTP 1.1»

Solicitando descargar un archivo.

Sigamos entonces con nuestra práctica: ya sabemos que no vamos a mostrar un archivo index.html -ni índice.html– sino que mostramos un listado de archivos, ahora nos iremos a la carpeta donde clonamos el “fork” del proyecto py-qt-share y lanzamos allí nuestro servidor web Python.

«python3 -m http.server 8000» carpeta proyecto py-qt-share
«python3 -m http.server 8000» carpeta proyecto py-qt-share

Allí tenéis de una vez la tres líneas completas, un abreboca, pero veamos la primera y segunda líneas -olvidemos la tercera, por el momento- y abramos de nuevo otra ventana terminal donde lanzamos el comando curl para retribuir el listado de archivos disponibles:

orden GET HTTP 1 sobre carpeta py-qt-share
orden GET HTTP 1 sobre carpeta py-qt-share

Una vez recibimos e interpretamos el HTML solicitamos de nuevo con otro comando GET el fichero README.md, observemos lo que responde:

curl -i README.md
curl -i README.md

Diseccionemos la respuesta:

Server: SimpleHTTP/0.6 Python/3.5.2
Date: Sun, 16 Apr 2017 02:55:23 GMT
Content-type: application/octet-stream
Content-Length: 575
Last-Modified: Sat, 15 Apr 2017 23:33:16 GMT

¿Cómo es posible que en el Content-type nos indique que es una aplicación? 😐😐😐

Sabemos plenamente que un fichero con extensión .md generalmente contiene un lenguaje de marcado tipo MarkDown (de nuevo, mirad nuestro otro tutorial relacionado), si acaso se asemeja más a un text/html que a una aplicación ¿Qué piensan ustedes?

Los lectores más experimentados nos responderán “¿de dónde saca que .md es un MIME type?” Pues veamos los tipos principales definidos en RFC-2046:

The “text” media type is intended for sending material which is
principally textual in form. A “charset” parameter may be used to
indicate the character set of the body text for “text” subtypes,
notably including the subtype “text/plain”, which is a generic
subtype for plain text.

De manera independiente a la opinión que tengamos si MarkDown es un fichero de texto o una aplicación debemos primero analizar en qué se basan para programar nuestro servidor web en Python para clasificar los archivos que listamos para compartir con otras computadoras. Analizemos la función dedicada a esto:

  def guess_type(self, path):
     """Guess the type of a file.
     Argument is a PATH (a filename).
     Return value is a string of the form type/subtype,
     usable for a MIME Content-type header.
     The default implementation looks the file's extension
     up in the table self.extensions_map, using application/octet-stream
     as a default; however it would be permissible (if
     slow) to look inside the data to make a better guess.
     """

Como bien podemos leer PRIMERO se trata de identificar el archivo por la extensión del archivo, lo cual es una solución rápida -y sucia- de identificar con qué tipo de datos estamos lidiando, y por defecto asumimos que es una aplicación “application/octet-stream” ya que ponerse a la tarea de abrir cada archivo y ver su contenido es una tarea muy tediosa (y que puede bloquear nuestro ordenador si tenemos demasiados ficheros almacenados).

“import mimetypes”

Es por ello necesario que pasemos a revisar la librería que importamos llamada mimetypes. Si revisamos la documentación de Python al respecto pues… la metodología es la misma, ¡”adivinar” por la extensión del fichero!

No obstante se apoyan en un método más “científico”: revisar las aplicaciones que tenemos en nuestro sistema operativo para poder ofrecer así una mayor variedad de opciones:

knownfiles = [
 "/etc/mime.types",
 "/etc/httpd/mime.types", # Mac OS X
 "/etc/httpd/conf/mime.types", # Apache
 "/etc/apache/mime.types", # Apache 1
 "/etc/apache2/mime.types", # Apache 2
 "/usr/local/etc/httpd/conf/mime.types",
 "/usr/local/lib/netscape/mime.types",
 "/usr/local/etc/httpd/conf/mime.types", # Apache 1.2
 "/usr/local/etc/mime.types", # Apache 1.3
]

Actualizado el jueves 20 de julio de 2017.

En este enlace de la “Web del Programador” podreis descargar un fichero en formato PDF con la mayoría de las extensiones de fichero conocidas, muy completa lista, os lo recomendamos.


De acá notamos que rapidamente podemos agregar nuestras propias extensiones, empezemos por la primera línea /etc/mime.types: en una ventana terminal metemos el comando “sudo nano /etc/mime.types” y podremos ver un encabezado parecido al siguiente:

###############################################################################
#
#  MIME media types and the extensions that represent them.
#
#  The format of this file is a media type on the left and zero or more
#  filename extensions on the right.  Programs using this file will map
#  files ending with those extensions to the associated type.
#
#  This file is part of the "mime-support" package.  Please report a bug using
#  the "reportbug" command of the "reportbug" package if you would like new
#  types or extensions to be added.
#
#  The reason that all types are managed by the mime-support package instead
#  allowing individual packages to install types in much the same way as they
#  add entries in to the mailcap file is so these types can be referenced by
#  other programs (such as a web server) even if the specific support package
#  for that type is not installed.
#
#  Users can add their own types if they wish by creating a ".mime.types"
#  file in their home directory.  Definitions included there will take
#  precedence over those listed here.
#
###############################################################################

En el último párrafo especifican que podremos crear nuestros propios tipos de ficheros por medio de un archivo en nuestro directorio personal de datos (“home”) y que tendrá preferencia aquella lista sobre esta. Pero si modificamos la lista principal los efectos tomarán para todos los usuarios en el ordenador donde estemos compartiendo archivos.

Es así que agregamos la siguiente línea, ya sea al final o buscáis el último grupo de líneas:

text/markdown                                   md
mime types text markdown md
mime types text markdown md

Previamente, por medio de nuestro editor de texto favoritos, nano, buscamos que la palabra “markdown” no esté registrado ni tampoco la extensión de archivo “md“. Luego le damos guardar y salir y relanzamos de nuevo nuestro servidor web escrito en Python para compartir archivos y solicitamos descargar de nuevo el archivo markdown del guion que le hicimos “fork” antes de resubirlo a GitHub. Nuestro navegador ahora nos mostrará el diálogo de descarga de una manera diferente y hasta nos propondrá editarlo con nuestro editor de texto con entrono gráfico favorito gedit, mirad:

Abriendo README.md
Abriendo README.md

Y claro, solicita abrirlo con gedit porque le estamos especificando que es un archivo de texto pero con una nueva clasificación “por nosotros propuesta”, tipo markdown.

Presentando ficheros markdown como HTML.

Para ensanchar nuestros conocimientos haremos un ejercicio interesante en cuanto a agregar funcionalidades a nuestro servidor web escrito en Python. La idea consiste en agregar una librería a nuestro Python y el cual permite convertir código markdown en HTML. Para ello debemos primero descargar el software necesario, tanto para Python 2.X como Python 3.X, mirad la imagen:

pip install markdown
pip install markdown

Una vez tengamos instalada la librería, corremos una terminal Python y hacemos unas cuantas pruebas y confirmar como convierte en código HTML lo que le pasemos en código markdown:

import markdown
import markdown
Python 3.5.2 (default, Nov 17 2016, 17:05:23) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import markdown
>>> print(markdown.markdown("* Lista "));
<ul>
<li>Lista </li>
</ul>
>>> print(markdown.markdown("# Título 1 "));
<h1>Título 1</h1>
>>>

Ya tenemos nuestro conversor; la idea que tenemos en mente es mostrar todo archivo con extensión “.md” en la carpeta que compartimos en ambos formatos pero con una diferencia: el enlace mostrado en el navegador en realidad NO es un fichero real en disco sino una “traducción” del fichero tipo markdown que sí existe en disco. Por supuesto nuestro navegador web al hacer click en uno de estos enlaces y recibir la cabecera de datos que recibe del servidor web Python se comportará de diferentes maneras: ante un fichero “.html” no ofrecerá guardar en disco sino directamente mostrarlo por pantalla. Esto que queremos hacer pareciera no tener sentido alguno pero si alguna vez llegáis a estudiar el lenguaje PHP entenderéis como un guión escrito en un lenguaje es convertido a un lenguaje de marcación como HTML. Cuesta un poco acostumbrarse a esta manera de trabajar en PHP pero una vez que uno le toma el gusto todo va sobre ruedas.

Ahora presentamos un código de prueba para exhibir un fichero markdown por pantalla en formato HTML, para ello también echaremos mano de la librería codecs que viene por defecto en las instalaciones de Python, veamos (recordad que tenemos abierta una ventana terminal en la carpeta que estamos compartiendo):

>>> import markdown
>>> import codecs
>>> archivo_md = codecs.open("README.md", mode="r", encoding="utf-8")
>>> texto = archivo_md.read()
>>> print(markdown.markdown(text);
<p><strong>Utilidad escrita por el sr. Elías Rodríguez Martín</strong></p>
<p><a href="https://linuxgnublog.org/es/compartir-archivos-facil-y-rapidamente-gracias-a-python/">Entrada hecha en Linux GNU Blog para compartir archivos con Python</a></p>
<p><em>Adición hecha por Jimmy Olano para soportar caracteres no ascii (utf-8) en os.chdir()</em></p>
<p><a href="http://www.ks7000.net.ve/2017/04/15/python-http-server/">Entrada hecha en KS7000 + WP para ampliar el alcance de dicho guion</a></p>
<p><a href="https://www.gnu.org/licenses/license-recommendations.html">Propongo tenga una licencia Apache que es adecuada para pequeños proyectos 8-)</a></p>

Por supuesto que hay algunos detalles que corregir: primero se debe colocar el encabezado del archivo HTML, luego el “cuerpo” que es el código anterior y al final las etiquetas de cierre del archivo HTML. Segundo se debe comprobar que el código sea “limpiado” y presentado correctamente ya que proviene de una fuente “no confiable”. Para ello recomiendan una herramienta llamada Bleach (Blanqueador) el cual se debe instalar via pip y no explicaremos más para no poner pesada esta entrada (más pesada, queremos decir).

Ya tenemos la idea de lo que vamos a hacer, ahora analizamos el código que vamos a modificar el cual podemos inspeccionar y descargar desde este enlace. En realidad son dos funciones que modificaremos: la función que muestra los ficheros en un archivo virtual en formato HTMl con un listado de los archivos a compartir y luego la otra función que entrega el ficero en sí mismo.

La primera función es llamada list_directory y la segunda es llamada do_GET y ambas pertenecen a la clase SimpleHTTPRequestHandler.

Fuentes consultadas:

En idioma castellano:

En idioma inglés:

CSS Grid Layout specification

La Norma de Diseño de Cuadrícula que próximamente estará disponible en los navegadores web nos permite diseñar una serie de elementos por medio del Diseño de Hojas en Cascada (Cascade Style Sheets o mejor conocido por su acrónimo de tres letras CSS) con una rapidez asombrosa y pocas líneas de código. Por cierto, la imagen de introducción a este artículo fue creada por medio de código, no utilizamos el ratón ni una sola vez.

CSS Grid Layout
CSS Grid Layout

Introducción.

En esta entrada describiremos muy brevemente lo que son HTML y CSS para así poder probar en avance -aún no es está implementado en los navegadores web- las nuevas Normas de Diseños de Cuadrícula. Vamos pues, en esta novedosa área del diseño de páginas web.

HTML.

El Hyper Text Markup Language o simplemente HTML es un lenguaje de marcado, tal como lo explicamos anteriormente por este vuestro humilde portal web. Una muy buena definición, en castellano, de dicho lenguaje de marcado la podeis leer acá en este enlace. Específicamente vamos por la recomendación 5 que se presentó en diciembre de 2012 y que progresivamente se ha ido incorporando a los modernos navegadores web, tanto de código fuente abierto como privativo. Pero es el software libre quien lleva la delantera en esto y es por ello que los programadores de Mozilla Firefox están siempre tratando de alcanzar a las recomendaciones (normas, de facto) planteadas: una labor de hormiga, un paso a la vez.

El dibujito de advertencia que os hemos puesto es, entonces, para advertiros que en vuestro navegador actual NO FUNCIONARÁN PARA NADA LOS EJEMPLOS CON QUE TRABAJAREMOS HOY (a la fecha de hoy 14 marzo 2017 ya fue actualizado Mozilla Firefox). Tal vez ustedes pensarán que es una total y absoluta pérdida de tiempo si dichas normas cambian o, peor aún, nunca se llega a implementar en navegador web alguno (o son retiradas en su uso), pero oigamos a Eduardo Galeano: “para eso son las utopías, para mantenernos en movimiento”. Más adelante os explicaremos como instalar la sempiterna versión Beta de Mozilla Firefox: Nightly.

CSS.

Cuando presentamos el tema lo dijimos: vamos a ir muy rápido en los conceptos básicos para poder presentar la nueva norma de diseño de cuadrícula. Si HTML es un lenguaje de marcado basado en etiquetas podemos decir entnonces que viene a ser como el chasís y motor de nuestro automóvil y he aquí que el CSS viene a ser la carrocería y pintura del mismo. Como ya podéis sospechar, tanto en páginas web y como en automóviles, los humanos estamos es pendientes de las formas y colores la presentación de los elementos, y esto ya cae dentro del ámbito del gusto de cada quien.

Con HTML podremos crear nuestra propia página web.

CSS es un lenguaje que describe el estilo de un documento HTML.

CSS describe cómo los elementos HTML deberían ser mostrados.

Es por ello que siempre hemos considerado que CSS es y será la norma que nos ahorrará gran trabajo pues nos centraremos en imaginar y escribir las etiquetas HTML mínimas necesarias para nuestros programas [entradas, botones, listas, etcétera enlazadas o no con alguna(s) base de datos] y con CSS y JavaScript (eso sí, acompañado de base de datos) podremos ofrecer a nuestros usuarios unas plantillas básicas de presentación que ellos y ellas podrán escoger e incluso personalizar (por ello el uso de base de datos para luego poder recuperar esas preferencias). Pero no no extendamos más en este punto y sigamos adelante con nuestro objetivo principal, acompañadnos, por favor.

Prerrequisitos.

Firefox Mozilla Nightly.

Se tiene estimado que el 7 de marzo de 2017 salga a la luz pública la versión 52 de Mozilla Firefox y por consiguiente el apoyo a al “CSS Grid Layout“. Mientras tanto debemos utilizar la versión de avanzada, que siempre está y estará en versión BETA (una versión para un público reducido y previo a su lanzamiento) la cual es llamada Nightly. Acá os advertimos de nuevo: en este navegador no den nada por sentado, habrán cosas que se mejorarán, otras que se corregirán y algunas que no irán a la versión definitiva siguiente. De más está deciros que cualquier error que veaís lo podréis colaborar en su corrección, COLABORAD, pero no salgáis a criticar por las redes sociales porque no es una versión definitiva. Además, si todos nos diéramos a la tarea de criticar por ganar fama o popularidad ¿Quién demonios se va a dedicar a programar? ¡Alguien tiene que trabajar, colaborad, por favor!

Instalando Nightly en Ubuntu.

Para instalarlo debemos tener permiso de administrador o usuario root, abrimos una ventana terminal e introducimos los siguientes comandos:

 sudo add-apt-repository ppa:ubuntu-mozilla-daily/ppa
 sudo apt-get update
 sudo apt-get install firefox-trunk

Una vez descargados aproximadamente 46 megabytes de datos comprimidos, se procederá a su instalación y ocupará 156 megabytes en disco duro. Una observación importante que acota al final de la instalación es que debemos cerrar todas las ventanas que tengamos abiertas con Mozilla Firefox o de lo contrario tenderemos problemas, eso es un indicativo de que las librerías entre Mozilla Firefox 51 (a la fecha) y Nightly se comparten.

sudo apt-get install firefox-trunk
sudo apt-get install firefox-trunk

Instalando Nightly en Debian.

Aún usamos Debian 7, en honor a la verdad nos hemos quedado rezagados en eso porque siempre nos decantamos más por Ubuntu. La mala noticia es que no hallamos, de buenas a primera, un repositorio para esa versión, sin embargo observamos que para la versión 9 abundan repositorios, intentad fortuna con el siguiente a ver si podéis vosotros solitos.

CSS Grid Layout specification.

¿Qué es la Norma de Diseño de Cuadrícula CSS?

El Diseño de Cuadrícula nos permite separar apropiadamente el orden de los elementos desde la fuente contra su presentación visual. Como diseñador esto significa que eres libre de cambiar la ubicación de los elementos de la página en función del dispositivo que sea presentado sin necesidad de comprometer la sensible estructura de un documento HTML y siempre con un diseño responsivo.

Para el Real Diccionario de la Lengua la palabra responsivo significa “perteneciente o relativo a la respuesta” pero acá en programación de ordenadores lo enfocamos en que la respuesta viene representada por un tamaño de pantalla. Esto es así debido al la proliferación de dispositivos móviles (entiéndase, principalmente, teléfonos celulares o móviles) que tienen diversos tamaños de pantalla, pero no os llaméis a engaño, ya estos aparatitos están, de hecho, sustityendo a los ordenadores personales. Si queréis ver una prueba de lo que hablamos, y si utilizáis Firefox, probad y haced click en el menú desplegable “Herramientas” -> “Desarrollador web” -> “Modo de diseño adaptable” (o por medio del teclado pulsad de manera simultánea CONTROL+INVERSO+M).

Presentado lo anterior esperamos os habréis dado cuenta del futuro que os presentamos en este blog, ¡pinta bien y promete!

Terminología de cuadrícula.

Rápidamente os presentamos los conceptos que debéis conocer y manejar bien antes de comenzar a editar código alguno, debemos saber exactamente los nombres de los elementos.

Líneas de cuadrícula.

Son las líneas que “maquillan” a la cuadrícula, pueden ser horizontales o verticales. Podremos referirnos a ellas con un número o nombre, la mejor analogía serían las líneas de una hoja de cálculo, elemento abstracto que es conocido pro la mayoría de los usuarios de ordenadores. Acá una figurita, por si las dudas.

Lineas de rejillaPistas de cuadrícula.

Una pista de cuadrícula es toda el área entre dos líneas de cuadrícula. Dibujo de nuevo:

Pista de cuadrículaCelda de cuadrícula.

Una celda de caudrícula es la menor área posible a representar y se define como toda el área delimitada entre dos líneas verticales y dos líneas horizontales.

Celda de cuadrículaÁrea de cuadrícula.

Un área de cuadrícula también delimitada por dos líneas horizontales y dos líneas verticales pero contiene dos o más celdas de cuadrícula.

Área de caudrícula

Ahora que tenemos nuestras definiciones básicas podremos comenzar nuestro tutorial en sí.

Archivos base.

Bien podemos escribir un solo documento HTML que incluya CSS o bien podemos escribirlos en archivos aparte, escoged lo que os más os guste para estos fines didácticos. En todo caso presentamos el código básico para cada uno de ellos.

Un solo documento HTML.

<!doctype html system "about:legacy-compat">
<html lang="es-419">
  <head>
    <meta charset="utf-8" />
    <title>CCS Grid Layout.</title>
    <style>
      <!-- el código CSS aquí -->
    </style>
  </head>
<body>
   <div>
     <div>A</div>
     <div>B</div>
     <div>C</div>
     <div>D</div>
     <div>E</div>
     <div>F</div>
   </div>
</body>
</html>

Con un archivo CSS externo.

Para colocar nuestro código en un archivo externo tomaremos el código anterior pero en vez de colocar <style>…</style> simplemente colocaremos una sola línea con el siguiente código:

 <link rel="stylesheet" type="text/css" href="su_hoja_de_estilo.css">

Insertando estilo en cada línea.

Si la opción anterior -un archivo CSS externo- es la mejor opción ya que por medio del lenguaje PHP podemos generar un “link rel” apuntando a diferentes archivos .ccs para cada usuario, la tercera opción nos parece la menos adecuada pues se debe generar en cada línea de código HTML las instrucciones CSS. Para ello haríamos algo como esto:

 <h1 style="color:blue;margin-left:30px;">Encabezado 1 azul con margen izquierdo a 30 píxeles</h1>

Lo único bueno es que esta opción es la que veremos siempre, si la aplicamos, es decir: a medida que el navegador va aplicando los estilos el que prevalece es el último especificado, en este caso la línea en sí en código HTML. Por supuesto, si aplicamos código PHP perfectamente podemos programar para que, por ejemplo, cada vez que coloque un <h1> inserte un estilo para cada usuario pero li impractico de esto es que para cada línea repetiremos instrucciones, aumentando la cantidad de bytes a transferir: algo ineficiente. Si se hace esta declaración de alguna de las dos primera maneras solo tenemos que establecer una sola vez para todo el documento, a menos que en algún punto muy específico querramos presentar un encabezado 1 con un estilo diferente. Como véis, las posibilidades y combinaciones son infinitas.

Sintaxis de los comandos CSS.

Una regla de CSS está compuesta de un selector y un bloque de declaración que se aplica, por supuesto, al selector (o selectores) en el inicio. El bloque de declaración debe comenzar con un corchete de apertura “{” y uno de cierre “}” pudiendo ocupar varias líneas con propósitos de claridad  en nuestro código.

Selector  Declaración 1   Declaración 2     Declaración "n"
.h1     {   color:blue  ; font-size:12px  ;                 }
        propiedad:valor   propiedad:valor  

Si os preocupáis por agregar cantidades innecesarias de caracteres os recomendamos que a vuestro código fuente le apliquéis una “precompilación” antes de subirlas a vuestro servidor en producción, el proceso se basa en eliminar los espacios innecesarios a fin de obtiner un código compacto; no obstante si vosotros optáis por comprimir los datos antes de enviar de vuestro servidor web el tema de los espacios en blanco y retornos de carro no tendrá mayor incidencia porque como se repiten tanto son candidatos ideales para comprimirlos.

Definiendo nuestro primera cuadrícula.

A nuestro código base le vamos a hacer las siguientes modificaciones en el código HTML:

<div class="envoltorio">
  <div class="caja a">A</div>
  <div class="caja b">B</div>
  <div class="caja c">C</div>
  <div class="caja d">D</div>
  <div class="caja e">E</div>
  <div class="caja f">F</div>
</div>

Y en el código CSS le colocaremos los siguientes valores:

body {
  margin: 40px;
}

.envoltorio {
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-gap: 10px;
  background-color: #fff;
  color: #444;
}

.caja {
  background-color: black;
  color: green;
  border-radius: 7px;
  padding: 15px;
  font-size: 150%;
}

Fijémonos en la clase envoltorio y sus valores entre corchetes:

  • display: grid“: indica al navegador que deseamos una “dibujar” una rejilla.
  • grid-template-columns“: indicamos el ancho de cada columna (e implícitamente el número de ellas).
  • grid-gap“: acá indicamos el espacio que queremos dejar entre cada una de las pistas de cuadrícula.

Resultado ejemplo N° 1.

El resultado es el siguiente (probadlo en vuestro Mozilla Firefox Nightly):

Definiendo una cuadrícula
Definiendo una cuadrícula

Actualizado el jueves 9 de marzo de 2017.

Ya tenemos instalado el Mozilla Firefox 52:

El código de este ejemplo debería ser mostrado correctamente, si tenéis la versión 52 instalada en vuestro ordenador (esto lo logramos en WordPress colocando estilo CSS directamente dentro de la línea de cada instrucción HTML):

A
B
C
D
E
F

Especificando un orden exacto de los elementos.

Para este ejemplo aprovecharemos que hemos “enumerado” las celdas de nuestra cuadrícula con las letras del abecedario, vamos a establecer nuestro siguiente tinglado: ABC/DEF –> DAF/EBC.

Código HTML.

Para este ejemplo reutilizaremos el código mostrado en el archivo base, no redundaremos, subid y mirad por favor.

Código CSS.

Para este ejemplo reutilizaremos el ejemplo anterior pero agregaremos al final el siguiente código que especifica el orden en que queremos mostrar los elementos.

.a {
        grid-column-start: 2;
        grid-column-end: 3;
        grid-row-start: 1;
        grid-row-end: 2;
    }
    .b {
        grid-column-start: 2;
        grid-column-end: 3;
        grid-row-start: 2;
        grid-row-end: 3;
    }
    .c {
        grid-column-start: 3;
        grid-column-end: 4;
        grid-row-start: 2;
        grid-row-end: 3;
    }
    .d {
        grid-column-start: 1;
        grid-column-end: 2;
        grid-row-start: 1;
        grid-row-end: 2;
    }
    .e {
        grid-column-start: 1;
        grid-column-end: 2;
        grid-row-start: 2;
        grid-row-end: 3;
    }
    .f {
        grid-column-start: 3;
        grid-column-end: 4;
        grid-row-start: 1;
        grid-row-end: 2;
    }

Fijaos bien en la numeración de los siguientes elementos CSS:

  • grid-column-start
  • grid-column-end
  • grid-row-start
  • grid-row-end

Resultado ejemplo N° 2.

Especificando un orden exacto de los elementos.
Especificando un orden exacto de los elementos.

Usando código abreviado para especificar un orden exacto.

En este ejemplo obtendremos el mismo resultado del ejemplo N° 2 pero utilizando un código abreviado: en vez de utilizar un comando de inicio y otro de cierre usaremos un solo comando acompañado de los valores numéricos de inicio y fin separados por una barra invertida, veamos:

  .a {
    grid-column: 2 / 3;
    grid-row: 1 / 2;
  }
  .b {
    grid-column: 2 / 3;
    grid-row: 2 / 3;
  }
  .c {
    grid-column: 3 / 4;
    grid-row: 2 / 3;
  }
  .d {
    grid-column: 1 / 2;
    grid-row: 1 / 2;
  }
  .e {
    grid-column: 1 / 2;
    grid-row: 2 / 3;
  }
  .f {
    grid-column: 3 / 4;
    grid-row: 1 / 2;
  }

Es de hacer notar que en el mismo orden que los escribamos en el código CSS, así mismo será progresivamente dibujado en pantalla por el navegador web. Si cometemos algún error (por ejemplo, asignando o superponiendo celdas) será mostrada el último elemento que haya ocupado la celda(s) en cuestión. También veremos que un elemento podrá ocupar una o más celdas contiguas.

Utilizando un solo comando para especificar orden exacto.

De nuevo obtendremos el mismo resultado del ejemplo N° 1 y 2 pero con un solo comando: grid-area. Para ello le pasaremos los parámetros de la siguiente manera (separados por una barra invertida “/”):

  • Fila de inicio
  • Columna de inicio.
  • Fila de finalización.
  • Columna de finalización.

Código CSS.

Como es un solo comando, por elegancia usaremos una sola línea para cada uno de ellos:

    .a { grid-area: 1 / 2 / 2 / 3; }
    .b { grid-area: 2 / 2 / 3 / 3; }
    .c { grid-area: 2 / 3 / 3 / 4; }
    .d { grid-area: 1 / 1 / 2 / 2; }
    .e { grid-area: 2 / 1 / 3 / 2; }
    .f { grid-area: 1 / 3 / 2 / 4; }

Colocando elementos que ocupen más de una celda.

Para este ejemplo N° 4 agregaremos dos elementos más: G y H para hacer notar que sucede si un elemento ocupa más de una celda. Haremos que el elemento A ocupe dos celdas horizontales contiguas (celda 1-1 y 1-2) y el elemento B dos celdas verticales contiguas (celda 1-3 y 2-3).

Código HTML.

<div class="envoltorio">
  <div class="caja a">A</div>
  <div class="caja b">B</div>
  <div class="caja c">C</div>
  <div class="caja d">D</div>
  <div class="caja e">E</div>
  <div class="caja f">F</div>
  <div class="caja g">G</div>
  <div class="caja h">H</div>
</div>

Código CSS.

Solo especificaremos una ubicación específica a los elementos a, b, c y d pero notad como son desplazados los elementos restantes e hasta la h:

    .a { grid-column: 1 / 3; grid-row: 1    ;}
    .b { grid-column: 3    ; grid-row: 1 / 3;}
    .c { grid-column: 1    ; grid-row: 2    ;}
    .d { grid-column: 2    ; grid-row: 2    ;}

Hemos formateado el código de tal manera que notéis rápidamente la diferencia: hemos omitido el valor final.

    .a { grid-column: 1 / 3; grid-row: 1 / 2;}
    .b { grid-column: 3 / 4; grid-row: 1 / 3;}

Resultado ejemplo N° 4:

Colocando elementos que ocupen más de una celda
Colocando elementos que ocupen más de una celda

Percatad que es indiferente si al código CSS le eliminamos los elementos c y d: automáticamente el navegador web los coloca en la celda inmediatamente disponible ¡y el resto de los elementos también!

Colocando elementos que ocupen más de una celda con la palabra clave “span”.

El verbo “to span” en inglés significa “extender” en castellano, pues bien, podemos especificar el inicio (columna o fila) pero especificaremos cuantas celdas queremos extender. Esto facilita , mentalmente, las ubicaciones: solo especificamos el inicio y cuantas celdas se extiende.

También haremos un cambio en como se define la cuadrícula con un comando nuevo:

  • grid-template-rows: especifica el ancho de cada fila (anotaremos tantos valores como filas queremos tener).
  • Si los elementos exceden en cantidad a los valores anteriores, el navegador utilizará los valores por defecto que a bien tenga establecer.

Código CSS.

.envoltorio {
 display: grid;
 grid-gap: 10px;
 grid-template-columns: 100px 100px 100px;
 background-color: #fff;
 color: #444;
 }
.caja {
 background-color: black;
 color: green;
 border-radius: 5px;
 padding: 20px;
 font-size: 150%;
 }

 .a { grid-column: 1 / span 2; }
 .b { grid-column: 3 ; grid-row: 1 / span 2;}
 .e { grid-column: 1 / span 3; grid-row: 3 ;}

Resultado ejemplo N° 5.

Colocando elementos que ocupen más de una celda con la palabra clave "span"
Colocando elementos que ocupen más de una celda con la palabra clave “span”

Rejillas y líneas con nombres.

Código en HTML.

Simplificaremos este ejemplo con solamente cuatro elementos y os explicaremos en la sección CSS qué es lo que queremos realizar.

<div class="envoltorio">
  <div class="caja a">A</div>
  <div class="caja b">B</div>
  <div class="caja c">C</div>
  <div class="caja d">D</div>
</div>

Código en CSS.

Vamos a abstraernos aún más en este punto, ¿recordáis la introducción y que numeramos las líneas de las filas y las columnas? Pues podemos asignarles un nombre a cada una de ellas, pero necesitamos un comando o comandos para declarar dichas variables. De nuevo os presentamos dos instrucciones anteriores:

  • grid-template-columns
  • grid-template-rows

Ambas nos permiten almacenar valores en variables pero con una sintaxis especial: los paréntesis rectos o corchetes “[]” que permiten asignar el nombre y luego, como hemos visto, podemos especificar el ancho en diferentes unidades (píxeles, porcentajes, ect.); mirad el código, observad bien como os hemos estructurado e indentado las líneas:

body {
 margin: 40px;
}

.envoltorio {
  display: grid;
  grid-gap: 10px;
  grid-template-columns:
    [col1-ini] 100px
    [col2-ini] 100px
    [col3-ini] 100px
    [col3-fin];
  grid-template-rows:
    [fil1-ini] auto 
    [fil2-ini] auto 
    [fil2-fin];
  background-color: #fff;
  color: #444;
 }

.caja {
  background-color: #444;
  color: #fff;
  border-radius: 5px;
  padding: 20px;
  font-size: 150%;
}

.a {
  grid-column: col1-ini / col3-ini;
  grid-row: fil1-ini ;
}
.b {
  grid-column: col3-ini ;
  grid-row: fil1-ini / fil2-fin;
}
.c {
  grid-column: col1-ini;
  grid-row: fil2-ini ;
}
.d {
  grid-column: col2-ini ;
  grid-row: fil2-ini ;
}

Visualización del código, ejemplo N° 6.

A estas alturas imaginamos que ya tenéis la nueva versión de Mozilla Firefox, así que os presentamos no por imagen sino por código con estilo en cada línea el resultado de este ejemplo:

A
B
C
D

Rejillas y lineas con nombres extendiendo con palabra clave “span”.

Retomamos el ejemplo anterior (el código HTML es el mismo) pero simplificaremos las filas, veamos.

Código en CSS.

body {
  margin: 40px;
}

.envoltorio {
  display: grid;
  grid-gap: 10px;
  grid-template-columns: [col1] 100px [col2] 100px [col3] 100px [col4] 100px ;
  background-color: #fff;
  color: #444;
}

.caja {
  background-color: #444;
  color: #fff;
  border-radius: 5px;
  padding: 20px;
  font-size: 150%;
}

.a { grid-column: col1 / span 2;}
.b { grid-column: col3 / span 2;}
.c { grid-column: col1         ;}
.d { grid-column: col2 / span 3;}
.e { grid-column: col1 / span 4;}

Observemos los nombres que asignamos a cada columna y el cómo podemos referirnos a cada una de ellas. Este ejemplo colocamos nombres que a decir verdad no ahorran trabajo alguno ni ofrecen claridad: col1 es más largo que usar un simple número 1, pero acá el concepto es nombrar las columnas para nosotros , mentalmente, ubicarnos mejor. Es por ello que proponemos cambiar los nombres de la siguiente manera (eliminamos atributos para simplificar y realzar nuestro punto):

.envoltorio {
 grid-template-columns: [izq] 100px [centro] 100px [centro] 100px [der] 100px ;
}

.a { grid-column: izq      / span 2;}
.b { grid-column: centro 3 / span 2;}
.c { grid-column: izq              ;}
.d { grid-column: centro 2 / span 3;}
.e { grid-column: izq      / span 4;}

Ya diferenciamos que la primera columna es izq, las dos del centro las nombramos iguales y la derecha pues der. He aquí que con izq y der no tenemos ninguna duda de su uso pero las dos del centro debemos numerarlas debido a que le colocamos el mismo nombre a ambas (celdas b y d). En el próximo ejemplo N° 8 ahondaremos más en estos detalles.

Visualizando el resultado del ejemplo, ejemplo N° 7.

A
B
C
D
E

Ejemplo N° 8: comando “repeat”.

Ya aprendimos que podemos nombrar las lineas de cuadrícula y de paso les podemos asignar el mismo nombre porque le agregamos un espacio y luego el número de línea de cuadrícula para referirnos a ellas y evitar confusión. El comando que permite hacer esto es el comando grid-template-columns, ahora bien, hemos trabajado con pocos elementos de filas y columnas pero imaginemos que son 10, 15 o más filas y/o columnas… ¿cómo podemos definir la malla?

El “chiste” de la programación es ahorrarnos trabajo y nuestra rejilla debe estar definida, así que debemos escribir todas y cada una de las filas/columnas al navegador. A fin de ahorrarnos trabajo “inventaron” el comando repeat() para colocar entre paréntesis los valores que queremos repetir, y así escribimos menos.


Finalizando el tema.

Así nos despedimos por el día de hoy, no sin antes presentaros el código que utilizamos para presentar este humidle tutorial que espero os haya gustado y os sea útil a futuro, ¡gracias por vuestra atención!

Código en HTML.

<div class="envoltorio">
 <div class="caja a">A</div>
 <div class="caja b">B</div>
 <div class="caja c">CSS</div>
 <div class="caja d">D</div>
 <div class="caja e">E</div>
 <div class="caja f">F</div>
 <div class="caja g">G</div>
 <div class="caja h">HTML</div>
</div>

Código en CSS.

body {
 margin: 40px;
}

.envoltorio {
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-gap: 10px;
  background-color: #fff;
  color: #444;
}

.caja {
  background-color: #444;
  color: #fff;
  border-radius: 10px;
  padding: 20px;
  font-size: 150%;
}
.d { border-radius: 47px; }
.c { background-color: blue;}
.f { border-radius: 20px;}
.h {
 grid-column: 2/3;
 background-color: orange;
}

CSS Grid Layout

Actualizado el 14 de marzo de 2017: HTML con estilo CSS en cada línea.

Es más complejo escribirlo así pero es la manera más fácil para que WordPress muestre las mallas en Mozila Firefox 52 o superior:

<div style="display: grid; grid-template-columns: 100px 100px 100px; grid-gap: 10px; background-color: #fff; color: #444;">
 <div style="background-color: #444; color: #fff; border-radius: 10px; padding: 20px; font-size: 150%;">A</div>
 <div style="background-color: #444; color: #fff; border-radius: 10px; padding: 20px; font-size: 150%;">B</div>
 <div style="background-color: #444; color: #fff; border-radius: 10px; padding: 20px; font-size: 150%;background-color: blue;">CSS</div>
 <div style="background-color: #444; color: #fff; border-radius: 10px; padding: 20px; font-size: 150%;border-radius: 47px;">D</div>
 <div style="background-color: #444; color: #fff; border-radius: 10px; padding: 20px; font-size: 150%;">E</div>
 <div style="background-color: #444; color: #fff; border-radius: 10px; padding: 20px; font-size: 150%;border-radius: 20px;">F</div>
 <div style="background-color: #444; color: #fff; border-radius: 10px; padding: 20px; font-size: 150%;">G</div>
 <div style="background-color: #444; color: #fff; border-radius: 10px; padding: 20px; font-size: 130%;grid-column: 2/3; background-color: orange;">HTML</div>
</div>

Visualización si tenéis instalado Mozilla Firefox 52 o superior.

A
B
CSS
D
E
F
G
HTML

Fuentes consultadas.

En idioma castellano.

En idioma inglés.

Youtube’s tutorials:

CSSconf EU 2014 | Rachel Andrew: CSS Grid Layout

En idioma francés:

Agradecimiento público por difundir el conocimiento:

 

 

apache2 htacces

Mejorando la seguridad en Apache2 .htaccess

En una entrada anterior enseñamos como configurar mod_rewrite en nuestro .htaccess para poner a “punto de caramelo” nuestro Apache2 pero ahora es necesario preveniros de “haber abierto la caja de Pandora”: nuestro servidor web está expuesto a tácticas de intromisión y hasta toma de control por atacantes con malas intenciones. Sirva pues la presente para complementar y ayudaros a proteger vuestros equipos.

Apache mod_rewrite
Apache mod_rewrite

Prerequisitos.

Es bueno que leaís nuestro tutorial para configurar mod_rewrite pero si soís más avanzado os decimos de una vez que tenemos configurado ya un servidor Apache2 sobre Ubuntu 16 en una red de área local con la dirección 192.168.1.47

Para ser más exactos, corremos Apache 2.4 y podemos conocer cuál versión tenemos instalada abriendo una ventana terminal y ganando acceso como “root” o administrador:

root@KEVIN:/home/jimmy# apache2 -v
Server version: Apache/2.4.18 (Ubuntu)
Server built: 2016-07-14T12:32:26

Otra cosa que tenemos activado es el tratamiento de archivos .html o .htm como .php lo cual abre la posibilidad a que nuestra seguridad quede expuesta si alguien logra acceder a escribir en nuestro .htaccess (de nuevo os recordamos que todo está explicado en nuestra entrada anterior sobre como configurar mod_rewrite). Eso quiere decir que tenemos la siguiente instrucción en el archivo .htacces:

AddType application/x-httpd-php .html .htm

Al estar así configurado pasamos a estudiar las posibles brechas en seguridad.

apache2 htacces
apache2 htacces

Lo bueno, lo malo y lo feo.

Recordando la famosa película de vaqueros así clasificaremos las tretas y estrategias, poned atención que cada una de ellas es un caso particular a estudiar, pausar y seguir adelante para, al final, tener un panorama completo de la estrategia a seguir que más convenga a nuestro entorno de trabajo.

Empezaremos por lo malo, luego lo feo y de último lo bueno que podemos hacer.

Lo malo.

php_value auto_append_file.

Vale decir que este comando php_value bien puede estar ubicado ya sea en “PHP config”, “virtualhost settings” o en un archivo .htaccess que es el caso que nos ocupa y más específicamente el valor auto_append_file porque coloca al final de nuestra página web (en este ejemplo didáctico el archivo index.html que trae por defecto Apache al ser instalado) los valores que tengamos en nuestro archivo hosts con la siguiente instrucción:

php_value auto_append_file /etc/hosts

El resultado sería el siguiente:

php_value auto_append_file etc hosts
php_value auto_append_file etc hosts

Que para nuestro servidor de pruebas nos aporta muy poca información pero imaginad si lo tenéis en un servidor en producción y de paso sea compartido por otros sitios web, dicha información sería muy útil a los atacantes.

Otra variante de esta treta es incluir al archivo .htacces en sí mismo y adicionalmente algún código php. Por ejemplo podemos agregar el comando phpinfo(); con el cual podemos visualizar el entorno de variables con que trabajamos y buscar así software específico para nuestra configuración y poder de esta manera tomar control completo, si fueramos atacantes.


1
2
php_value auto_append_file .htaccess
#&lt;?php phpinfo();
php_value auto_append_file htaccess phpinfo
php_value auto_append_file htaccess phpinfo

php_flag display_errors 1

Hasta ahora hemos visto inyecciones de código que se ejecutan cada vez que es cargado y mostrado un archivo .html ¿pero que tal colocar una bomba eventual? Si, como habéis leido, “eventual” es diferente a una bomba de tiempo, una bomba eventual se ejecuta cuando sucede algún disparador. Para este caso el disparador del evento es cuando nos hayamos equivocado programando algún código php, con la salvedad de que el atacante a nuestra web haya colocado un “script” que se lanza en este suceso, pero veamos el código:

php_flag display_errors 1
php_flag html_errors 1
php_value docref_root "'><script>alert('¡Programador perdedor!);</script>"

En la primera y segunda línea lo que se hace es activar la rutina de aviso de errores (que bien en vez del parámetro “1” puede tomar el valor “on”) y en la tercera línea es donde se inserta el código malicioso en sí (acá simplemente mostramos un aviso recriminando el error). Esto sería el equivalente a “castigar” al programador al cometer un error y el script que desencadene podría ser peor aún todavía. Por extraño comportamiento, esto produciría un muy extraño regocijo a nuestro atacante y esperad también ver algún código de aviso para el atacante que nos pudiera servir para dar con el paradero del delincuente digital.

Otra variante sería utilizar php_value docref_ext lo cual duplicaría las ejecuciones del script malicioso.

php_flag display_errors 1
php_flag html_errors 1
php_value docref_root "x"
php_value docref_ext "<script>alert(1);</script>"

QUERY_STRING

En lenguaje HTML y PHP es bien sabido que se puede pasar valores directamente por la barra de direcciones con simplemente agregar al final de la dirección web un signo de cierre de interrogación acompañado del nombre de la variable, un signo de igualdad y el valor de la variable. Si se desean pasar más valores se utiliza un et “&” y se repite el procedimiento. Esto es especialmente útil para iniciar sesión en una página web pero también abre la puerta a posibles robots que intenten, a lo largo de mucho tiempo, ir probando valores automáticamente hasta poder ingresar. Para cerrar esta posibilidad podemos hacer lo siguiente, consideremos el siguiente archivo llamado “bienvenido.hmtl“:

<?php
 echo '<html><body>Bienvenido ';
 if (isset($_GET['nombre'])) {
   $test = $_GET['nombre'];
 } else {
   $test = ' Invitado';
 }
 echo $test;
 echo '</body></html';
?>

Como podéis observar utilizamos el método $_GET a modo didáctico para poder hacer las pruebas sin necesitar de otro archivo con formulario que lo refiera. Si introducimos una consulta como la siguiente:

http://192.168.1.47/bienvenido.html?nombre=Pedro

Obtendremos la siguiente respuesta:

bienvenido html con pase de consulta
bienvenido html con pase de consulta

Pero como buscamos bloquear dichos “accesos directos” debemos modificar nuestro .htaccess de la siguiente manera:

RewriteEngine On
RewriteCond %{QUERY_STRING} .
RewriteRule ^bienvenido\.html /bienvenido.html? [L]

La primera línea sabemos que activa la maquinaría de reescritura de direcciones y la segunda es una condición que se cumple siempre: compara la consulta %{QUERY_STRING} (toda la subcadena de texto a la derecha del signo de interrogación) y lo compara con el metacaracter “.” que significa una cadena de texto con cualquier (cualesquiera) caracter(es) de cualquier longitud (1 ó más) para que lo ejecute el siguiente comando RewriteRule. Este comando simplemente pasa la dirección con el nombre del archivo en cuestión acompañado de la bandera [L] que le indica que no procese las siguientes líneas en el fichero .htaccess . El resultado sería que el fichero bienvenido.html (que contiene un guion de comandos escritos en lenguaje PHP) muestre el mensaje “Bienvenido Invitado” como si no hubiera pasado consulta alguna al servidor web.

bienvenido html con consulta bloqueada
bienvenido html con consulta bloqueada

Para suplementar lo anterior, son bien famosos los robots que hacen publicidad en los comentarios de las entradas de WordPress y por supuesto lo hacen con pases de consultas, las podemos filtrar con palabras claves y prohibirles el acceso. Famosos por ser bien insidiosos son los “spam” de medicamentos para la disfunción eréctil tales como “compre viagra en oferta”, vamos a realizar una regla adicional a lo anterior -pase de consultas-:

RewriteCond %{QUERY_STRING} \b(spill|cialis|ejaculation|erectile)\b [NC,OR]
RewriteCond %{QUERY_STRING} \b(erections|impotence|levitra|libido)\b [NC,OR]
RewriteCond %{QUERY_STRING} \b(fitex|sildenafil|tadalafilo?)\b [NC,OR]
RewriteCond %{QUERY_STRING} \b(viagra|duroval|viasek)\b [NC]
RewriteRule .* - [F]

Como apreciamos agregamos las marcas más conocidas pero aún faltan muchas más, como la lista es larga “encadenamos” cada RewriteCond con la bandera [OR] pero la última línea antes de RewriteRule NO debe contener [OR]. La otra bandera utilizada es [NC] para que coincida en la búsqueda en mayúsculas y/o minúsculas y para finalizar la bandera [F] para prohibir el acceso, que devuelva un código 403.

Poned atención en la palabra clave “tadalafilo?” ya que bloquea “tadalafil” o “tadalafilo” y en idioma castellano los nombres de principios químicos activos siempre la última letra produce sinonimías (otro ejemplo: “ciprofloxacino” y “ciprofloxacina” significan exactamente lo mismo). Esto es así debido que en inglés el género no toma mayor importancia (y en el lenguaje cotidiano da pie a muchas situaciones graciosas que aprovechan guiones de series de televisión “sitcom”) y cuando se traduce al castellano puede tomar valores ambivalentes y el algunos casos hasta extraños. Al contrario, en este campo, en el idiom inglés son pocos los casos que esto sucede (de hecho ellos GUSTAN de palabras cortas, no hablemos ya si gustan de sinonimias, además ellos utilizan marcas comerciales como nombres propios para los principios químicos activos), un caso muy particular es el medicamento contra la depresión llamado “Prozac” y por algunos es escrito como “Prosac”: en nuestras reglas de expresiones regulares lo podemos marcar como “pro[sz]ac” para que sea detectado -ambas escrituras- y bloqueado en los comentarios de cada entrada pública de nuestro blog.

Lo feo 🙁

php_flag engine 0

Con esta única línea en nuestro archivo .htaccess hará que automáticamente podamos descargar completamente un archivo .html o .php aunque igual se ejecute el guión php obtenemos el código fuente completo, incluidas contraseñas, comentarios, los diversos include hacia otros ficheros, etc. que hayamos colocado en dichos archivos. Nos parece que es la más maliciosa inyección de código en nuestro servidor.

LO BUENO 😎

IndexIgnore *

De manera predeterminada un servidor web Apache siempre buscará mostrar un archivo llamado “index.html” o “index.php” pero si dicho archivo -por alguna u otra razón- no se encuentra entonces se le mostrará al visitante -o atacante- los archivos y subdirectorios presentes, mirad un ejemplo:

lista directorios index of
lista directorios index of

Para evitar dicho comportamiento debemos agregar a nuestro .htaccess las siguientes líneas:

IndexIgnore *
Options +FollowSymLinks All -Indexes

Al guardar y revisitar mostrará lo siguiente:

Listado negado de directorio
Listado negado de directorio

De tener algún problema con la opción “+FollowSymLinks” (mirad imagen siguiente) simplemente comentarla y guardar de nuevo el archivo .htaccess.

Internal serve error
Internal serve error

DirectoryIndex

Mencionamos en el punto anterior que siempre buscará servir un fichero “index” pero ¿qué tal si tenemos dos ficheros llamados “index.php” e “index.html” en el mismo directorio?

Pues con la orden DirectoryIndex podemos ordenar cual se ejecuta primero -y de no conseguirse ejecuta el segundo-, esto puede ser de utilidad si queremos “forzar” cuál clase de archivos queremos siempre mostrar.

DirectoryIndex index.html index.php

En este ejemplo -recordad la configuración de servidor- obligamos que sea mostrado “index.html” primero (y dentro tenemos el código php necesario que será ejecutado por nuestra configuración especial .htaccess) y de no conseguirse buscaría mostrar “index.php”. Un atacante podría colocar su propio “index.php” y modificar .htaccess para camiar este orden. Nosotros preferimos utilizar solamente lo siguiente:

DirectoryIndex index.html

Así al faltar “index.html” no muestra ninguna página e intentará mostrar los archivos y subdirectorios opción la cual le eliminamos la visualización en el punto anterior.

FileETag MTime Size

Habilitar los ETag en un servidor web trae doble beneficio: por una parte ahorramos en tráfico de bytes lo cual redunda en rapidez al cargar nuestro sitio y el beneficio de la seguridad adicional.

ETags funciona identificando en un archivo TAGS las características que identifican unívocamente para fichero que pondemos a disposición del público. Es transmitido y guardado por el cliente en un caché, luego si recargan la página el servidor envia de nuevo el ETag y si el recurso no ha cambiado pues se ahorra el envio.

Por parte de la seguridad es útil si utilizamos rsync desde un servidor que origina datos (y que no está expuesto a la internet) y sirve para “alimentar” uno o varios servidores espejos -o nodos-. Hay un interesante artículo titulado “Rsync: Sincroniza tus carpetas o respalda tus archivos en Linux – Debian – Ubuntu – Derivados” escrito por el experimentado usuario Twitter @Xombra donde encontraréis mayores detalles acerca del uso de rsync como estrategia de respaldo.

 

Si utilizamos un servidor único podemos agregar INode, cuando hay varios servidores web para una misma página los ETags se vuelven inútiles ya que en cada servidor cada INode es diferente con lo cual incluso incrementa la carga de trabajo en nuestro sitio web. Es debido a esto que se les activa solamente dos atributos: tiempo (MTime) y tamaño (Size).

Para habilitarlo debemos colocar lo siguiente en nuestro archivo .htaccess (pendientes con detalle del INode):

FileETag INode MTime Size

SetEnvIf user-agent

Otra manera de proteger en alguna manera nuestro Apache es denegando a ciertos agentes que visiten nuestro sitio. Cada navegador web envia su identificación al solicitar una página web y a nuestro servidor podemos denegar el acceso (esto no quiere decir que a su vez los atacantes “disfrazen” su software de ataque como algún navegador web popular). La sintaxis que debemos usar es la siguiente:

SetEnvIf user-agent "Wget" stayout=1
SetEnvIf user-agent "Indy Library" stayout=1
SetEnvIf user-agent "libwww-perl" stayout=1
SetEnvIf user-agent "Download Demon" stayout=1
SetEnvIf user-agent "GetRight" stayout=1
SetEnvIf user-agent "GetWeb!" stayout=1
SetEnvIf user-agent "Go!Zilla" stayout=1
SetEnvIf user-agent "Go-Ahead-Got-It" stayout=1
SetEnvIf user-agent "GrabNet" stayout=1
SetEnvIf user-agent "TurnitinBot" stayout=1
deny from env=stayout

En realidad la última línea es la que bloquea los agentes, fijaros bien que la primera línea bloquea al famoso wget que si bien no es un programa malicioso en sí mismo si que se utiliza en scripts que pueden ser mal utilizados. Si tenéis algún script propio que acceda a vuestro servidor web tened cuidado en marcar como comentario dicha línea.

wget bloqueado por htaccess
wget bloqueado por htaccess

Fuentes consultadas.

En idioma inglés.

Lo malo:

Lo bueno:

Lo feo:

Apache mod_rewrite

Tutorial para configurar mod_rewrite en Apache sobre Ubuntu

Para los que “montamos” páginas web siempre es útil ocultar las extensiones de nuestros archivos a ser servidos y así despistar a posibles atacantes pero es mejor aún para que nuestros usuarios les sea más fácil recordar nuestras secciones e incluso promociones publicitarias, ¿ya tenemos vuestra atención?

Introducción.

En un mundo donde ya prácticamente todo el mundo introduce una búsqueda en Google o DuckDuckGo para llegar a nuestra página web -exponiéndose a redirecciones hacia páginas falsas por los buscadores web- pues nosotros nos empeñamos en utilizar la barra de direcciones de nuestro navegador web recomendado, Mozilla Firefox.

Es así entonces que podemos publicar alguna promoción en algún medio de comunicación como televisión o prensa y queremos que se pongan en contacto con nosotros por medio de una página web que a tal efecto hayamos programado para ello. Dicha dirección podría ser:

nuestrodominio.com/contacto

Como véis no incluimos “www” ni tampoco las dobles barras (de hecho Tim Berners-Lee se disculpó públicamente por haber hecho la redundancia y hacernos escribir billones de veces ese caracter adicional) ni “http:” -la mayoría de los navegadores web completan automáticamente la dirección- pero mejor aún hemos obviado la extensión del archivo .html, algo que consideramos podría confundir a cualquier usuario común (sí, que hasta los “nativos digitales” también se pueden equivocar).

La intención de este tutorial es CONFIGURAR nuestro servidor web para que acepte dicha dirección y redirija a nuestros posibles clientes de manera transparente y así, a futuro, trabajemos y aumentemos nuestros ingresos 😉 .

Prefacio.

Aunque no estamos escribiendo un libro, estas páginas web algún día las podríamos recopilar en un ejemplar, por eso el uso de la palabra “prefacio“. Lo que necesitaremos para nuestra práctica didáctica es un ordenador con Ubuntu 16 instalado (que también vale este tutorial para Ubuntu 14) al cual le instalaremos Apache2. Para nuestro caso nuestra máquina tiene una dirección IP fija en nuestra red área de local 192.168.1.47 CAMBIAD lo que veaís aquí por vuestra propia dirección IP local. Lo que acá escribimos es válido también para cuando queráis montar vuestro servidor de producción en la internet y solo está limitado por las restricciones que os imponga vuestro proveedor de hospedaje. Este tutorial es completo y el escenario sería o bien una máquina virtual o real que alquileís a un proveedor de alojamiento (es más costoso que alojamiento compartido) o vuestro ordenador con una dirección IP fija que os venda vuestro ISP y que os conécteis bien sea por “ADSL” o “frame relay“.

Instalando Apache Web Server:

Abrimos una ventana de comandos (si no sabéis cómo, leed nuestro tutorial) e introducimos el siguiente comando:

sudo apt-get update
sudo apt-get install apache2

La primera línea actualiza los paquetes disponibles para nuestra versión GNU/Linux que tengamos instalado (Ubuntu 16 en este ejemplo) y la segunda línea instala el servidor web Apache2, software que ha evolucionado mucho desde los años 90. Nótese que usamos “sudo” para tener derechos de administrador o “root” y deberemos colocar la contraseña respectiva (luego el sistema obvia esta solicitud si corremos varios comandos seguidos en corto período de tiempo). Podremos ver algo muy parecido a esto, si todo sale bien:

apt-get install apache2
apt-get install apache2

Para probar que tenemos nuestro servidor instalado podemos navegar hasta nuestra propia dirección IP o en su defecto podemos utilizar la palabra clave “localhost” y eso sí, en la barra de direcciones de nuestro navegador (los buscadores web NO mostrarán enlace hacia nuestro servidor).

Apache2 Ubuntu Default Page
Apache2 Ubuntu Default Page

Habilitando mod_rewrite.

Antes de meternos de lleno con mod_rewrite cumplimos con avisaros que también existe la función mod_alias que es muchísimo más sencilla para resolver rápidamente ciertas situaciones -e incluso cuenta con los comando más avanzados llamados “<Location>” y “<LocationMatch>“- .

Pero si queremos evolucionar y disponer de una herramienta poderosa (y compleja) estudiaremos mod_rewrite. Para activar mod_rewrite debemos ejecutar las siguiente líneas:

sudo a2enmod rewrite
sudo service apache2 restart

La segunda línea sirve para que el servicio o “daemon” reinicie con la configuración deseada. En el ambiente GNU/Linux son muy parcos y estoicos, si todo va bien simplemente veréis de nuevo el indicador de la línea de comando “prompt” -pero al finalizar el primer comando nos indica que falta alguna instrucción que sea importante para finalizar el comando-. ES DECIR no espéreis a cada rato mensaje de confirmación de comando ejecutado -otra cosa, en raras y contadas ocasiones deberemos hacer un reinicio completo de nuestro ordenador, con reiniciar los servicios respectivos tiene para seguir funcionando luego de nuestros cambios-.

Como ya sabéis los comandos en GNU/Linux diferencian letras mayúsculas de minúsculas y por supuesto debemos escribir muy bien los comandos, no como nosotros que nos equivocamos pero luego correjimos, mirad:

sudo a2enmod rewrite
sudo a2enmod rewrite

Configurando .htaccess

Ahora debemos crear un archivo (oculto, mirad el puntito que precede el nombre del fichero) muy importante en el funcionamiento de Apache. Si lo tenemos ubicado en el directorio raíz de nuestro servidor web se aplicará a todas las subcarpetas que tengamos pero cada subcarpeta podrá tener su propio “.htaccess” que regirá para la carpeta donde esté ubicado (y a su vez las subcarpetas que contenga) obviando las instrucciones que hayamos colocado en nuestro “.htacces raíz”.

Pero antes, por razones de seguridad, debemos tener acceso (desde Apache) para crear y escribir dicho fichero, usamos nano -o vuestro editor de texto favorito- para modificar el siguiente archivo:

sudo nano /etc/apache2/sites-enabled/000-default.conf

Tras dentro del cual debemos insertar lo siguiente (notad los comentarios que insertamos en castellano en la imagen más abajo:)

  <Directory /var/www/html>
     Options Indexes FollowSymLinks MultiViews
     AllowOverride All
     Order allow,deny
     allow from all
  </Directory>
000-default.conf
000-default.conf

Es sumamente importante indentar las líneas (en nano lo podéis hacer rápidamente pulsando la tecla TAB para cada sangría) y respetar mayúsculas y minúsculas. Luego debemos reiniciar el servicio web Apache con el consabido comando:

sudo service apache2 restart

Como información adicional os contamos que el archivo “000-default.conf” es el archivo por defecto del primer dominio que sea servido por nuestro ordenador, es decir, podremos a futuro alojar varios dominios en una sola máquina. De este modo el segundo dominio utilizará el archivo “001-default.conf” y así sucesivamente, pero ¿cómo reconoce nuestro servidor web cual dominio entregar? Estad atentos más adelante en este tutorial os daremos noción de ello -y a futuro publicaremos una entrada totalmente dedicada a configurar un servidor Apache con varios dominios virtuales-.

Creando .htaccess

Ya que tenemos configurado a Apache para que acepte nuestro .htaccess procedemos a crearlo. Para ello debemos utilizar nuestro editor de archivos de texto favorito (usaremos nano en este caso) y escribiremos lo siguiente:


1
sudo nano /var/www/html/.htaccess

Y le agregamos una sola línea:


1
RewriteEngine on
RewriteEngine on
RewriteEngine on

Guardamos y luego debemos garantizar su acceso para los demás usuarios, nosotros o cualquiera otro usuario que edite nuestra página web (recordad que lo creamos con la credencial de administrador o “root”):


1
sudo chmod 644 /var/www/html/.htaccess

¡Y listo! Ya tenemos configurado nuestro .htaccess pero como decía Santo Tomás “hasta no ver, no creer” así que vamos a probar si es verdad que funciona.

Creando nuestra pequeña página web.

Como dijimos al principio haremos una página de contacto sin mayores pretensiones, en este ejemplo indicando nuestro correo electrónico de manera tal que no sea capturada por los robots que esparcen “spam” a diestra y siniestra (para una explicación más a fondo visitad nuestro tutorial sobre HTML5):

<html>
        <head>
                <title>Contacto.</title>
        </head>
        <body>
                <h1>Correo electr&oacutenico:</h1>
                <p> contacto EN 192.168.1.47 </p>
        </body>
</html>
contacto.html
contacto.html

Y al navegar desde nuestra barra de dirección de nuestro navegador web observamos que tranquilamente podemos obviar la extensión del archivo y nuestro Apache dará por bien servida a nuestros propósitos sin mayor configuración, pero…

contacto
contacto

… si escribimos “Contacto” (o cualquiera de sus variaciones en mayúsculas o minúsculas) veremos algo que se asemeja a esto:

Contacto
Contacto

Para solucionar esto hemos de echar mano en el archivo .htaccess y hacer uso de las expresiones regulares.

Usando expresiones regulares o racionales.

De antemano: Apache utiliza los conceptos de expresiones regulares o racionales desde el punto de vista del lenguaje Perl 5, ciertas diferencias hay que tenerlas muy en cuenta si usamos otros lenguajes que soportan o tienen librerías que permiten el uso de expresiones regulares (a saber hoy en día, sin que sea tajante la lista: AWK, C++, Java, JavaScript, PCRE, PHP, Python y .NET framework ).


1
sudo nano /var/www/html/.htaccess

Volvemos a modificar nuestro archivo .htaccess y agregamos la siguiente línea:


1
RewriteRule ^contacto.html$ contacto.html [NC]

Guardamos en inmediatamente la regla es puesta en funcionamiento, lo podemos comprobar al buscar nuestra página (recordad poner vuestra propia direción IP o dominio web) /Contacto.html y todas sus variantes, probad y volved.


Explicamos entonces la expresión regular -o racional- utilizada, el significado de cada metacaracter:

  • “contacto.html”: es el nombre del fichero al cual queremos “redirigir” de manera “transparente” al usuario, es decir, mostrará la página a pesar de como escriba el visitante el enlace web (mayúsculas o minúsculas).
  • “^”: representa todo el enlace a la izquierda de nuestra palabra clave (en nuestro caso el nombre de un fichero pero esto no es necesariamente así todo el tiempo, ya veremos más adelante).
  • “$”: representa todo el enlace a la derecha de nuestra palabra clave, éste y el anterior metacaracter actúan a modo de delimitadores, lo podemos ver de esa manera para simplificar su uso.
  • “[NC]”: es una bandera o banderín que indica que use indistintamente minúsculas y/o mayúsculas en nuestra palabra clave.

En conclusión que nuestros usuarios podrán escribir “contacto” con o sin extensión, en mayúsculas y/o minúsculas (todas sus combinaciones) -probad- más sin embargo las siguientes expresiones devolverán una respuesta 404 “página no encontrada”:

  1. 192.168.1.47/contacto.html/
  2. 192.168.1.47/contacto.htm
  3. 192.168.1.47/contact

En el primero se trata de abrir un subdirectorio, en el segundo y el tercer caso se trata de abrir un archivo totalmente diferente (casos que al final también analizaremos y trataremos).

Actualizado el sábado 5 de agosto de 2017.

Que este tema de las expresiones regulares da para una entrada completa en nuestro blog, por la red social Twitter econtramos una excelente imagen que lo explica muy rápidamente y a continuación leímos las opiniones de varios programadores al respecto. Os debemos ese tutorial y en cuanto hallemos tiempo libre de nuestro trabajo de ganarnos el pan de cada día lo haremos.

 

Reglas de “Rewrite”.

De las expresiones regulares o racionales, ese tema solo, solito él, da para una entrada completa, sin embargo ya tenéis la práctica (si algo no tenéis claro subid y practicad de nuevo) y es por ello que acá estudiaremos unas cuantas reglas más avanzadas del comando “RewriteRule” -valga la redundancia multilingüe, si es que eso existe- utilizando las expresiones regulares o racionales para usos más avanzados, ¡vamos!

RewriteRule patrón sustitución bandera
  • Cada regla ha de colocarse en cada archivo .htaccess al principio de la línea con la palabra clave “RewriteRule“.
  • A continuación escribiremos el patrón a buscar en el enlace recibido por nuestro servidor web (ya comentamos de entrada mera que los navegadores web modernos agregan “http://www”, colocan todo el dominio en minúsculas -NO los subdominios y archivos- y hasta completan “.com” si se escribe dominio y se presiona CTRL+INTRO).
  • Sustitución, osea, lo que queremos enviar a nuestro servidor web y que se comporte como si el mismo usuario lo hubiera escrito tal cual (si queréis, pensad en este proceso como un corrector ortográfico automático a toda petición web que llegue).
  • Opcional: bandera o banderín para modificar la regla.

Ejemplo sencillo: imaginad que ahora en nuestra cuenta Twitter, nuestro perfil, colocamos un enlace web para que los interesados sepan nuestro correo electrónico pero queremos reutilizar la paginita web “contacto.html” para ello, pues lo que debemos hacer es anteceder en nuestras reglas lo siguiente:

RewriteRule ^correoe$ contacto.html [NC]
RewriteRule ^contacto.html$ contacto.html [NC]

Como podeís observar en la primera línea, simplemente si un visitante escribe:

http://www.nuestrodominio.com/correoe

pues simplemente nuestro servidor web recibirá la orden de mostrar nuestro archivo “contacto.html” y listo, sin mayor trabajo hemos solucionado otro “problema” pero la cosa va más allá, vamos a preguntarnos ¿Qué tal si escribimos “Contacto.Html” en vez de “contacto.html”? Como bien sabéis en GNU/Linux (y los servidores web e internet en general) las mayúsculas se distinguen de las minúsculas, no son lo mismo a pesar que nuestro cerebro las siga tratando como iguales, ¿qué sucedería?

RewriteRule ^correoe$ Contacto.htmL
RewriteRule ^contacto.html$ contacto.html [NC]

Advertencia imagen pequeña

No, no estaís equivocados, en efecto, el archivo “Contacto.htmL” NO existe en nuestro servidor web pero igual nos “devuelve” el contenido de “contacto.hmtl”, resulta y acontece que cada regla se ejecuta una a una y la siguiente regla corrige lo que entrega la regla anterior -muchas otras personas lo ven como si se “sobreescribe” la una a la otra, pero en realidad nosotros lo vemos de manera muy similar al comando tubería “|” que utiliza el shell de GNU/Linux.

Anda, probad a gusto tu archivo .htaccess, quitad la segunda línea y ensayad, luego volved y seguiremos practicando otras cosillas.


Utilizando patrones alternos.

En este punto continuaremos con el ejemplo anterior: ¿qué tal si queremos escribir ambas reglas en una sola línea?

Para ello haremos uso del los paréntesis normales “()” y el metacaracter “|” que en este caso viene a significar “o” (“or” en idioma inglés) -no confundir con el comando grep que mencionamos párrafos arriba, son contextos diferentes debido a que están encerrados entre paréntesis-:

RewriteRule ^(contacto.html|correoe.html)$ contacto.html [NC]

Ya sabemos como funciona la regla, aquí lo nuevo es como expresamos el patrón y le estamos indicando que ya sea que recibamos “contacto.html” o “correoe.html” -en mayúsculas y/o minúsculas mirad la bandera– siempre “devolverá” la cadena de texto “contacto.html”, precisamente el nombre del fichero que mostrará nuestro servidor web. Incluso podemos ir más allá y quitar las extensiones “.html” del patrón e igual funcionará, probad esto:

RewriteRule ^(contacto|correoe)$ contacto.html [NC]

Utilizando el pase de parámetros.

De nuevo seguimos el hilo con el ejemplo anterior, ¿qué tal si quisiéramos saber cómo llegó nuestro usuario hasta nuestro servidor -preguntando por “correoe.html” o “contacto.html”?

Esto lo podemos lograr insertandole un poco de lenguaje PHP, pero vayamos por partes y configuremos nuestro ordenador:


En nuestro servidor web Apache debemos instalar las librerías que soportan PHP versión 7 (en Ubuntu 16):

apt-get install libapache2-mod-php
sudo a2enmod php7.0
sudo service apache2 restart
  1. En la primera línea instalamos las librerías php.
  2. En la segunda línea activamos php 7 para Apache.
  3. En la tercera línea reiniciamos el servicio Aapache.

Si todo va bien podremos examinar la configuración PHP con un archivo que podemos crear nosotros mismos con una línea: “<? phpinfo() ?>” y lo guardamos con el nombre que más nos guste. Al “llamarlo” por el navegador web nos mostrará algo parecido a lo siguiente:

PHP 7 en Apache 2 sobre Ubuntu 16
PHP 7 en Apache 2 sobre Ubuntu 16

NOTA: en un servidor “en producción” por razones de seguridad NUNCA debemos dejar un archivo con la función “phpinfo()” : haría que cualquier atacante conozca nuestro “entorno” y le sea más fácil utilizar herramientas específicas contra las versiones de software que tengamos instalado en nuestro ordenador configurado para trabajo público.


Ha llegado la hora, pues, de modificar nuestro .htaccess para que trabaje con lenguaje PHP:

AddType application/x-httpd-php .html .htm
RewriteRule ^(contacto|contacto.html|correoe)$ contacto.html?origen=$1 [NC,QSA]
  • En nuestro archivo .htaccess la primera línea indica a nuestro servidor Apache que trate los archivos .html y .htm como .php .
  • En la segunda línea añadimos la bandera “QSA” (“Query String Append”) la cual permite pasar de manera intacta la palabra clave recibida, tal cual fue escrita, por medio de un método GET al “interior” del archivo HTML (“?origen=$1”).
  • Por último el comodín $1 indica por cual de las opciones “entra” la consulta (si tuviéramos otro paréntesis con opciones “|” recuperaríamos dicha coincidencia o elección con $2 y así sucesivamente).
RewriteRule y variables seleccionadas
RewriteRule y variables seleccionadas

En nuestro archivo “contacto.html” modificamos para que reconozca las palabras claves “contacto” y “correoe”: con la primera escribiremos “Gracias por conocer nuestra promoción en TELEVISION” y a la segunda “Gracias por conocer nuestra promoción en PERIÓDICO”.

  • “contacto” -> “TELEVISION”.
  • “correoe” -> “PRENSA”.
<html>
  <head><title>Contacto.</title></head>
  <body>
    <?php
      $parametro = strtolower($_GET['origen']);
      $contacto = strpos($parametro,'contacto');
      if ($contacto !== false) {
        echo(' ¡Gracias por conocer nuestra promoción en TELEVISION!');
      }else{
        echo(' ¡Gracias por conocer nuestra promoción en PRENSA!');
      }
    ?>
    <h1>Correo electr&oacutenico:</h1>
    <p> contacto EN 192.168.1.47 </p>
  </body>
</html>

Como veís con el lenguaje PHP buscamos la palabra clave “contacto” para notificar que el cliente vio la promoción por televisión, el otro único valor posible es “correoe” ya que la regla mod_rewrite filtra lo que escribe el usuario.

  • Con el comando $_GET[‘origen’] obtenemos la cadena $1 del comando RewriteRule.
  • Con el comando strtolower() lo convertimos todo a minúsculas.
  • Con el comando strpos() obtenemos FALSO si no se haya la palabra clave, de lo contrario devuelve un valor mayor o igual a cero.
  • Teniendo en cuenta lo anterior se debe utilizar la comparación ($contacto !== false) por negación para obtener el resultado correcto.

Hasta acá hemos considerado que el usuario o visitante escriba ya sea “correoe” o “contacto” -con todas sus variantes, con o sin extensión (.html o .htm) pero ¿Qué ocurriría si, dado el caso, el navegante escribiera “correo”, es decir, obviara la última letra? En este caso nuestro servidor simplemente devolvería un mensaje de error 404 como este:

Ejemplo de página no encontrada.
Ejemplo de página no encontrada.

Podemos, con propósitos didácticos, ampliar nuestro estudio de Rewrite con un comando adicional: RewriteCond.

Reglas de “RewriteCond”.

El comando “RewriteCond” nos permite evaluar una condición y de ser cierta ejecutará la siguiente e inmediata línea “Rewrite” de lo contrario la saltará y seguira evaluando el resto de las líneas de nuestro fichero .htaccess (si es que hubieran más líneas). Otro punto a tener en cuenta es que se pueden tener varias líneas RewriteCond contínuas una después de la otra y si alguna se cumple se ejecutará la siguiente e inmediata línea “Rewrite”.

Veamos la sintaxis de RewriteCond:

RewriteCond cadena condicion banderas
  • RewriteCond: el comando en sí mismo que debe ser sucedido en la siguiente línea con un comando “RewriteRule”.
  • Cadena: lo que vamos a comprobar, la entrada de datos.
  • Condicion: lo que le vamos a aplicar a la cadena, con la que vamos a comparar y que nos devolverá un valor verdadero o falso.
  • Banderas: modifican el comportamiento de la condicion y va entre corchetes y separadas por comas, si son varias y tal como lo vimos con el comando “RewriteRule”.

Como vemos ya tenemos la teoría, ahora vayamos a la práctica. Seguiremos con nuestro ejemplo anterior: ¿qué sucede si el visitante de nuestra página web escribiera mal la dirección web (URI) y obtuviera un mensaje con error 404?

Podríamos “redirigir” la dirección solicitada hacia la página principal de nuestro servidor web de manera transparente con nuestro archivo .htaccess pero primero una advertencia:


Advertencia imagen pequeña

Esta NO es la manera correcta de tratar una visita a nuestra servidor web que no contenga, por alguna razón (página borrada, error del usuario, etc) una URI solicitada. Lo “legal” es manejar el error 404 con una página web personalizada (de hecho la que vemos es la que trae Apache por defecto) y recomendamos que transcurrido un tiempo necesario para su lectura sea redirigida automáticamente hacia nuestra página web principal (esto escapa a este tutorial pero podéis hacerlo con JavaScript o incluso PHP).

Para configurar nuestra propia página web personalizada para el error 404 podemos hacerla a nuestro gusto/diseño y nombrarla, por ejemplo, “404_personalizado.html” y ubicarla en el directorio raíz para luego agregar a nuestro archivo .htaccess la siguiente línea:

ErrorDocument 404 /404_personalizado.html

Retomando nuestro ejemplo podemos agregar a nuestro .htaccess las siguientes líneas que evaluarán y tratarán la entrada de la URL recibida y la ubicaremos al final del fichero para que sea ejecutada en último lugar (si la colocamos antes al llegar una consulta por “/correoe” automáticamente será redirigida a la página principal):

AddType application/x-httpd-php .html .htm
RewriteEngine on
RewriteRule ^(contacto|contacto.html|correoe)$ contacto.html?origen=$1 [NC,QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ %1

Las 3 primeras líneas ya las hemos explicado y aprendido ahora expliquemos las dos líneas agregadas:

  • “RewriteCond”: El comando que nos permite evaluar una condición.
  • “%{REQUEST_FILENAME}”: El archivo solicitado, luego de haber recibido la URI (con confundir con {REQUEST_URI} ).
  • “!”: es un operador lógico que invierte un valor, por ejemplo de falso a verdadero.
  • “-f”: Le indica a nuestro servidor que compruebe si es un archivo es “regular”, esto es, que esté bien escrito y que exista en nuestro ordenador -y devuelve verdadero si esto se cumple-.
  • Si no se cumple el punto anterior y devuelve falso con el operador “!” lo convertimos en verdadero y tenga la respuesta positiva para ejecutar la siguiente línea “RewriteRule”.
  • “RewriteRule”: con la respuesta positiva recibida comienza a trabajar comparando con el patrón siguiente.
  • “^(.*)$”: los metacaracteres “^” y “$” ya los conocemos, los nuevos son “.” y “*” que indican que compare -y acepte- cualquier caracter y cualquier cantidad de los mismos, es decir, acepte toda entrada posible (el punto indica que puede ser cualquier caracter y el asterisco indica que dicho caracter se puede repetir cualquier cantidad de veces). Como cumple con el patrón procede a aplicar la regla.
  • ¿Recuerdan la variable “$1” que nos permitía elegir que opción de un patrón recibíamos? Ahora con la variable “%1” nos permite pasar intacta la referencia recibida de la “RewriteCond” (la parte que corresponde a nuestro dominio) que desencadenó la ejecución de la “RewriteRule”.

En este punto consideramos prudente mostrar de forma un tanto gráfica la nomenclatura de

Un último ejemplo de “RewriteCond”.

Para finalizar este tutorial vamos a proponernos el bloquear el acceso a una dirección IP4 en particular. Para nuestros propósitos didácticos tenemos una red de área local con nuestro servidor web en 192.168.1.47 (la misma a lo largo de toda esta entrada) y una máquina virtual con la dirección IP4 192.168.1.78 la cual queremos bloquear y para ello agregaremos lo siguiente:


1
2
RewriteCond %{REMOTE_ADDR} ^(192\.168\.1\.78)$
RewriteRule (.*) - [F,L]

Pasamos a explicar línea por línea y comando por comando:

  • “RewriteCond”: comando para evaluar una condición.
  • “%{REMOTE_ADDR}”: una variable que contiene la dirección IP del visitante.
  • “^” y “$”: delimitadores izquierdo y derecho de la dirección IP recibida.
  • “(” y “)”: cadena a evaluar con expresion regular.
  • “\”: la barra invertida sirve para indicarle a nuestro servidor web que el punto a la derecha lo considere como símbolo y NO como metacaracter (ver ejemplo anterior de error 404).
  • Los números pues son la dirección IP a bloquear.
  • “RewriteRule”: es la línea que sirve a la(s) última(s) “RewriteCond”.
  • “(.*)”: indica que acepte cualquier cadena de texto -ver ejemplo arriba-.
  • “-“: un guión para que NO sustituya nada ya que la bandera hará el trabajo por nosotros -ver siguiente punto-.
  • “[F,L]”: son dos banderas con dos instrucciones diferentes, la letra “F” le indica que envie el “mensaje” de prohibido (en realidad devuelve un “error 403” el cual también podemos personalizar con un fichero .html a nuestro gusto y conveniencia tal y como lo hicimos con el “No encontrado 404”). La letra “L” es muy importante e indica que es la última (“last”) regla a aplicar y que no revise las siguientes (si las hubiere) líneas en .htaccess . Esto es así porque si de plano le prohibimos el acceso ¿para qué vamos a revisar reglas adicionales?

La probamos y veremos algo muy similar a esto:

403 Forbidden
403 Forbidden

Si por el contrario queremos que solamente esa dirección IP tenga acceso al servidor web (por ejemplo queremos”administrar” nuestro servidor desde esa única y exclusiva dirección IP, sin que nadie nos moleste) simplemente antecedemos el caracter lógico “!” que inverte la respuesta de la comparación.

En idioma inglés:

Enlaces hacia expresiones regulares:

En idioma japonés:

 

Let’s Encrypt @LetsEncrypt.

Let’s Encrypt” es un proyecto de la “Electronic Frontier Foundation” en colaboración con la “Linux Foundation” para promover uso del protocolo HTTPS.

For english speakers: this is a merely translation into castilian language of an article year ago published by “Electronic Frontier Foundation” (also known as EFF acronym) where it announces the starting project “Let’s Encrypt”.

Let’s Encrypt: Vamos a encriptar.

Esta es una mera traducción al idioma castellano de un artículo publicado a hace un año atrás por la “Electronic Frontier Foundation” (también conocida por su acrónimo EFF) donde anuncian el comienzo del proyecto “Let’s Encrypt” (vamos a encryptar -la web-). Los enlaces web originales del artículo están en idioma inglés sin embargo algunos otros que agregué por mi cuenta están en castellano para rápidamente ayudar a entender algunos conceptos, si es que deseaís ampliar tus horizontes. Sin más, aquí va:


Hoy la EFF se complace en anunciar “Let’s Encrypt”, una nueva iniciativa de Autoridad de Certificación (CA por sus siglas en inglés) que hemos comenzado junto a Mozilla, Cisco, Akamai, IdenTrust e investigadores de la Universidad de Michigan cuyo objetivo es limpiar las barricadas restantes para la transición de la web del protocolo HTTP al protocolo HTTPS.

A pesar de que el protocolo HTTP ha tenido un éxito enorme, es inseguro de manera inherente. Cada vez que usted utilice una página web HTTP, siempre estará vulnerable a los problemas, incluyendo robo de cuentas y usurpación de identidad, vigilancia y seguimiento de gobiernos, compañías o ambos en conspiración; inyección de guiones maliciosos dentro de páginas; y censura cuyo objetivo son palabras específicas o sitios web específicos. El protocolo HTTPS, aunque todavía no es perfecto, es una gran mejora en todos los frentes, y necesitamos mudar a futuro cada sitio web al protocolo HTTPS por defecto. Con un lazamiento programado para el verano (boreal) del 2015 la Autoridad de Certificación “Let’s Encrypt” automáticamente expedirá y administrará certificados sin costo para cualquier sitio web que los necesite. Configurar un servidor web de HTTP al HTTPS con esta Autoridad de Certificación será tan fácil como emitir un comando, o hacer click en un botón.

El más grande obstáculo para el despliegue del HTTPS ha sido la complejidad, la burocracia y el costo que los certificados que HTTPS requiere. Estamos familiarizados con los mensajes de advertencias y error producidos por certificados mal configurados. Esas advertencia son una pista de que HTTPS (y otros usos del TLS/SSLseguridad de la capa de transporte/capa de conexión segura-) depende de una complejidad horrororosa y una burocracia estructuralmente disfuncional para la autenticación.

Advertencia de no-certificado.
“Let’s Encrypt” eliminará la mayoría de los tipos de errores de advertencias de certificados.

Instalación rápida y segura.

La necesidad de obtener, instalar y administrar certificados de esa burocracia es la mayor razón para que los sitios web sigan usando HTTP en vez de HTTPS. En nuestras pruebas, típicamente le toma a un programador web de 1 a 3 horas habilitar la encriptación por primera vez. El proyecto “Let’s encrypt”apunta a resolverlo reduciendo el tiempo a 20 ó 30 segundos. Usted puede ayudar a probar e indagar más sobre cómo funciona el agente de software “Let’s Encrypt” en su vista previa para desarrollador u observe un video de éste en acción:

“Let’s Encrypt” empleará un número nuevo de tecnologías para una verificación automatizada de manejo seguro de dominios y emisión de certificados. Usaremos un protocolo que estamos desarrollando llamado ACME entre servidores web y la Autoridad de Certificación, la cual incluye apoyo para nuevas y fuertes normas de validación de dominios. También emplearemos conjuntos de datos de certificados distribuidos a lo largo y ancho del internet, tales como el propio Observatorio Descentralizado SSL de la EFFF, el de la Universidad de Michigan, y el Registro Transparente de Certificados de Google, para tomar decisiones de mayor seguridad con respecto si un certificado es de emisión segura.

La Autoridad de Certificación “Let’s Encrypt” será operada por una nueva organización sin fines de lucro llamada Grupo de Investigación de Seguridad en Internet (Internet Security Research Group -ISRG-). “Electronic Frontier Foundation” ayudó a juntar esta iniciativa con Mozilla y la Universidad de Michigan, y se ha unido en el lanzamiento con socios tales como Cisco, Akamai e IdenTrust.

El equipo central que trabaja en la Autoridad de Certificación “Let’s Encrypt” y agente de software incluye a James Kasten, Seth Schoen, y Peter Eckersley por parte de la EFF; Josh Aas, Richard Barnes, Kevin Dick y Eric Rescorla por parte de Mozilla; Alex Halderman y James Kasten por parte de la Universidad de Michigan.


Por último (y fué publicado el 19 de octubre de 2015) les invito a ver el fruto del trabajo realizado durante largos años de colaboración unificada, la primera página “¡Hola mundo!” con certificados intermedios de referencia cruzada, de nuevo traduzco para ustedes (si usted sabe traducir mejor POR FAVOR registrese y comente esta entrada):


“Let’s Encrypt” es segura.

Estamos muy complacidos en anunciar que hemos recibido las firmas cruzadas proporcionadas por IdenTrust, lo cual significa que nuestros certificados son ahora seguros en la mayoría de navegadores web. Esto es un hito significativo debido a que los visitantes de sitios web con certificados “Let’s Encrypt” pueden disfrutar de una experiencia de navegación segura sin que requiera ninguna configuración especial.

Ambos certificados intermedios “Let’s Encrypt”, llamados “Autoridad X1 Let’s Encrypt” y “Autoridad X2 Let’s Encrypt”, recibieron firmas cruzadas. Los servidores web necesitarán ser configurados con el certificado de firmas cruzadas apropiado como aprte de la cadena de confianza. El cliente “Let’s Encrypt” manejará esto automáticamente.

Usted puede ver un ejemplo de un servidor utilizando un certificado “Let’s Encrypt” bajo una nueva firma cruzada intermedia aquí.
Información personal vital y de negocios está circulando por internet con más frecuencia que nunca, y es tiempo de encriptar todo esto. Es por eso que hemos creado “Let’s Encrypt”, y estamos animados en ser el gran paso que nos acerce a brindar conexiones seguras a cada rincón de la web.


Actualizado el lunes 18 de abril de 2016.

Cada día son más y más personas que reportan del éxito de “Let’s Encrypt” y aseguran sus sitios web con este protocolo seguro de comunicación para mantener la privacidad y seguridad de los internautas.

 

Estamos seguros que algún día aseguraremos esta vuestra página web para ustedes ¡pero @CaracasHosting POR AHORA no me deja siquiera instalar mi propio certificado autogenerado!

<Eso es todo, por ahora.>