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.

PHP y cURL

Suena incoherente: usamos curl en nuestra línea de comandos frecuentemente para diversidad de tareas pero no sabíamos que el lenguaje PHP tiene su propia versión llamada, cómo no, curl. El asunto es cómo se implementa y qué podemos hacer, nosotros en la línea de comandos lo acompañamos en el trabajo con grep pero en PHP la cosa es un poco diferente, ¡vamos a averiguar cómo!

Introducción.

Exactamente cómo implementaron cURL en PHP no lo sabemos, tal vez PHP haga llamado directo al curl y recoja sus resultados, sirviendo entonces como intermediario solamente… No tiene sentido pero si analizamos que muchos sitios web compartidos con otros dominios tienen PHP pero a uno no lo dejan ingresar por la línea de comandos entonces ¡vaya que si vale la pena el trabajo intermedio!

Por otra parte puede ser que especulamos demasiado y los buenos desarrolladores de PHP tienen su propia versión… ¡pero recordad que trabajamos con Software Libre que permite la modificación y reutilización del código! Pero echemos una leve ojeada al comando curl.

Comando curl.

Ya sabemos como va es esto del software libre: hay más de 1400 colaboradores en curl y el proyecto está alojado en GitHub desde el año 2010; aceptan contribuciones bajo la forma de “pull requests”: en resumen uno copia y trabaja con esa copia privada modificandola -y mejorandola, por supuesto- y devolviendo el trabajo al original para su aprobación. No se garantiza que se acepte toda la propuesta, e incluso ellos podrán tomar ciertas cosas propuestas y otras no, o en el mejor de los casos todo vaya bien y nos convirtamos en el colaborador 1401… y así haremos nuestra contribución al Patrimonio Tecnológico de la Humanidad.

Pero ¿quiénes desarrollan curl? Daniel Stenberg -sueco, habitante de Estocolmo- es el principal desarrollador y comenzó el proyecto por allá en 1996 basado en el trabajo de un programador brasileño llamado Rafael Sagula. Esta sencilla herramienta herramienta carioca fue bautizada como httpget con unas cuantas centenares de líneas y Stenberg las amplió para liberarla en 1997 con el nuevo nombre de “HTTP proxy support”. Pero con el advenimiento de “nuevos” protocolos al proyecto tales como GOPHER y FTP pronto dejó de tomar sentido llamarlo solamente “HTTP”… así que ese mismo año vio la luz la versión número dos.

Para 1998 más protocolos y capacidades fueron agregados así que volvió a cambiar de nombre para la versión 4.0 -manteniendo la numeración de versiones- así que el 20 de marzo de ese año marca el nacimiento formal de curl. El nuevo nombre hace alusión al programa del lado del cliente, de allí la letra “c” inicial. Las otras tres letras os lo podéis imaginar ya: Uniform Resource Locator -URL- o Localizador de Recursos Normalizados.

El mismo Stenberg reconoce que hay muchos proyectos con el mismo nombre curl pero para la época que ellos lanzaron la versión cuatro no había (o conocían) de otros proyectos con el mismo nombre. Es por ello que nosotros al principio especulamos del origen de curl en el lenguaje PHP, pero es que ¡Incluso existe un curl desarrollado en software privativo! (no le haremos publicidad pues no nos pagan por ello, buscadlo vosotros mismos con DuckDuckGo). Tan famoso es que ya se considera como verbo en idioma inglés y muchos creen que es un protocolo pues lo tratan como tal pero ya sabemos que en realidad es una navaja suiza con muchísimas funciones.

curl para la línea de comandos.

En principio el comando curl fue desarrollado para scripts ya que sus entradas y salidas utilizan las ya famosas stdin y stdout. No ampliaremos más porque en este blog hallaréis información sobre su uso con la línea de comandos. El artículo que motivó la publicación de esta entrada está en el siguiente “tuit” y precisamente es para la línea de comandos -y pretendemos que corra en PHP curl-:

También hemos recopilado con el paso del tiempo otros usos notables del curl en la línea de comandos:

 

curl para su uso como librería.

A partir del año 2000 fueron desarrolladas, o mejor dicho, el código existente fue migrado completamente como librerías y a partir de allí se le hizo una interfaz de usuario para la línea de comandos. Está escrito en lenguaje C y aún hoy en día dichas bases siguen sustentando el proyecto con la ventaja que se puede reutilizar en otros proyectos y compilarlos todos juntos. Seguimos sospechando que precisamente eso hicieron en PHP pero esa es nuestra humilde opinión que como reafirmamos: en software libre este comportamiento es un honor a su filosofía de desarrollo: ejecutar, estudiar, distribuir, mejorar y redistribuir.

Versiones actuales y desarrolladores estrellas.

Nosotros en nuestro GNU/Linux Ubuntu 16 tenemos instalada la versión 7.40.00 pero en realidad la última versión estable es la 7.54.0.

Si bien son muchísimos los colaboradores, es justo mencionar los que más han contribuido en los últimos años de una manera marcada y constante:

  • Daniel Stenberg.
  • Steve Holme.
  • Jay Satiro.
  • Dan Fandrich.
  • Marc Hörsken.
  • Kamil Dudka.
  • Alessandro Ghedini.
  • Yang Tse.
  • Günter Knauf.
  • Tatsuhiro Tsujikawa.
  • Patrick Monnerat.
  • Nick Zitzmann.

Disipación de toda duda.

En este punto de nuestra investigación nuestras sospechas se hacen realidad: uno de los primero lenguajes en adoptar la librería curl es precisamente PHP el cual motoriza un 25% de las páginas web a nivel mundial. El extracto , en inglés, reposa en el libro electrónico -liberado con licencia “Creative Commons”- “Everything about curl“:

The libcurl binding for PHP was one of, if not the, first bindings for libcurl to really catch on and get used widely. It quickly got adopted as a default way for PHP users to transfer data and as it has now been in that position for over a decade and PHP has turned out to be a fairly popular technology on the Internet (recent numbers indicated that something like a quarter of all sites on the Internet uses PHP).
A few really high-demand sites are using PHP and are using libcurl in the backend. Facebook and Yahoo are two such sites.

La traducción hecha por nosotros al idioma castellano:

El software de enlace (librerías) de curl para PHP fue uno, cuidado sino, el primero de los enlaces que realmente captura y lo usa ampliamente. Rápidamente fue adoptado como una manera por defecto para transferir datos y se ha mantenido en esa posición por más de una década mientras tque PHP se ha convertido en una tecnología bastante popular en internet (cifras recientes indican que algo asó como una cuarta parte de todos los sitios web en internet utilizan PHP).

Realmente unos pocos sitios web de alta demanda están usando PHP acompañado de las librerías de enlace de curl corriendo entre bamabalinas. Facebook y Yahoo son dos de tales sitios.

Protocolos soportados por curl.

HTTP, HTTPS, FTP, FTPS, GOPHER, TFTP, SCP, SFTP, SMB, TELNET, DICT, LDAP, LDAPS, FILE, IMAP, SMTP, POP3, RTSP y RTMP (esos son todos, por ahora -y vienen más, no se detiene el proyecto-).

PHP curl.

Ahora si que pasamos a hablar del software que nos ocupa en este vuestro sitio web de compartición del conocimiento. Como ya hemos hablado bastante de historia y teoría pasamos directamente a describir cómo trabajar con PHP curl:

  1. Inicializar curl con curl_init().
  2. Pasarle los parámetros – esencial es la URL – con curl_setopt().
  3. Retribuir y mostrar -o guardar- con curl_exec().
  4. Cerrar y liberar recursos con curl_close().

Nuestro primer ejemplo práctico.

Lo siguiente que haremos es abrir una ventana terminal, tomar nuestro editor de texto favorito y escribir el siguiente código para ser guardado en un archivo que llamaremos php_curl.php:

<?php
    $objCurl = curl_init();
    curl_setopt ($objCurl, CURLOPT_URL, "http://www.soporteweb.com");
    curl_exec ($objCurl);
    curl_close ($objCurl);
?>

Por supuesto, llamad vuestro archivo como queráis, guardadlo en vuestra carpeta donde ejecute vuestro servidor PHP y dadle los permisos de lectura y ejecución necesarios. En la primera línea inicializamos, en la segunda línea le pasamos la dirección web deseada -un dominio que devuelve nuestra dirección IP asignada por nuestro ISP-, en la tercera línea lo ejecutamos y en la cuarta línea cerramos y liberamos recursos. Una explicación más detallada a continuación.

Inicialización.

Debemos crear una instancia y guardarla para futuras referencias, este objeto basado en curl nosotros lo llamamos $objCurl y este nombre es el que debemos pasar a los otros comandos. El comando curl_init() solamente acepta un parámetro, la URL que es un dato imprescindible, tal vez debido a ser tan importante fue el único que establecieron en este comando. Aunque en el ejemplo no lo colocamos por razones didácticas, de ahora en adelante “para que no se nos olvide” lo estableceremos siempre en la primera línea del script o guion del programa.

Configuración.

Este es el comando más denso, notad que le damos el nombre de configuración porque su nombre así lo sugiere: curl_setopt(), osea “setopt” -> “set options”. Acepta tres parámetros, separados por comas:

  • Primero debemos indicarle el objeto que contiene la inicialización de curl, en nuestro caso la variable $objCurl.
  • Segundo le pasaremos el tipo de valor que le pasaremos en el tercer parámetro, en nuestro caso la URL y la constante que lo define -nombrada de manera nemotécnica- es CURLOPT_URL.
  • El tercer parámetro es el valor en sí mismo de lo que indicamos en el segundo parámetro.

Debemos indicaros que usamos una sola línea para configurar, pero pronto veremos que esta parte es la más abultada por la infinidad de datos y tipos de datos que podemos pasar. Es mejor que vayaís preparando para aprender que esta sección siempre será multilínea y que debemos indentarla y escribirla lo más explícito posible para corregir a futuro de forma fácil nuestro código.

Ejecución.

Simplemente le decimos a PHP que hemos terminado de establecer lo que queremos obtener –o lo que queremos enviar, ya veremos más adelante- y acepta un parámetro que sigue siendo el objeto que hemos creado y configurado. En este punto ya os recordaremos que estamos trabajando con funciones y este comando devuelve verdadero o falso para indicar si tuvo éxito (para comparar la respuesta usaremos siempre “==” para estar seguros del tipo de variable y el resultado obtenido). En el ejemplo no colocamos ninguna variable que reciba el resultado del que hablamos como función ¿dónde está lo que nos interesa? En realidad el valor numérico (verdadero o falso) es lo que podemos guardar en una variable, el resto del resultados se va al stdout y eso será lo que enviaremos al navegador web que solicitó nuestro primer guión PHP sobre curl. Debido a esto recibiremos el mismo código HTML de la página que estamos solicitando (pero con los enlaces web absolutos cambiados).

Si probáis con descargar diferentes páginas, unas funcionarán, otras no, todo depende de si la página es estática, dinámica, si tiene JavaScript, en fin, cantidad de cosas que pueden NO ser compatibles con PHP curl: por eso debemos aprender las muchísimas opciones de configuración que nos sean útil en cada trabajo que se nos presente para ganarnos así el pan nuestro de cada día como Dios manda.

Liberación de recursos.

Os podrá sonar que nos contradecimos con lo siguiente: la función curl_close() se encarga de cerrar, como su nombre indica pero no devuelve resultado acerca del trabajo que le mandamos a realizar. Consideramos que esto es un “bug” porque a la hora de detectar dónde fugan recursos en nuestro servidor deberemos recurrir a otras herramientas apartes de PHP, pudiendo ser evitado esto con una sencilla rutina de nuestra parte e indicar que está sucediendo y qué está mal. Ah, perdón, casi lo olvidamos: el parámetro único que acepta es el objeto que creamos -y queremos destruir- con curl_init().

Nuestro primer ejemplo práctico pero mejorado.

Un sencillísima rutina de control de errores nos puede ahorrar muchísimos dolores de cabeza.

Nota: hay mejores métodos para el manejo de excepciones, pero aprendamos poco a poco. Ah, y nosotros lo llamamos “control de errores” y eso tampoco es el nombre correcto (excepciones) pero así nos abstraemos.

Por ello reescribiremos nuestro ejemplo pero con condicionales if~else:

<?php
  $objCurl = curl_init("http://www.soporteweb.com/");
  if ($objCurl == true) {
     $resul = curl_exec ($objCurl);
     if ($resul == true){
       curl_close ($objCurl);
     } else {
       echo "No se pudo ejecutar PHP curl<br>";
     }
  } else {
    echo "No se pudo inicializar PHP curl.<br>";
  }
?>

Notad que pasamos de una buena vez el URL en en el inicio con curl_init(). Además guardamos el valor del resultado en una variable, evaluamos el valor que tiene y ejecutamos o mostramos un mensaje apropiado según la respuesta obtenida. Muchos programadores y programadoras piensan que hacer nuestro software de esta manera, aparte de ayudarnos a nosotros mismo, abre las puertas a los hackers cuando se presentan excepciones -o errores, como les llamamos- porque “develan mucho”. Ese razonamiento es válido en el software privativo pero en el software libre no tiene asidero alguno porque cualquier hacker tiene acceso al código fuente, así que hagamos la depuración fácil para nosotros mismos.

Guardando el resultado en una “variable aparte”.

Como explicamos PHP curl envía al stdout la respuesta y asu vez eso lo pasamos al navegador, ¿qué tal si analizamos primero lo que recibimos y luego lo reenviamos? Por ejemplo, podríamos “acomodar” los enlaces absolutos de las imágenes que contiene la página web que llamamos (URL). Para ello vamos a emplear culr_setopt() con CURLOPT_RETURNTRANSFER establecido en el valor 1, mirad:

<?php
    $objCurl = curl_init("http://www.soporteweb.com");
    if ($objCurl == true) {
        curl_setopt ($objCurl, CURLOPT_RETURNTRANSFER, 1);
        $resul = curl_exec ($objCurl);
        if ($resul == true){
            curl_close ($objCurl);
            print "Nuestra direccion IP es: ";
            print $resul;
        } else {
            echo "No se pudo ejecutar PHP curl<br>";
        }
    } else {
        echo "No se pudo inicializar PHP curl.<br>";
    }
?>

Y así “manipulamos” el resultado con el texto que coloreamos en verde; ahora vamos un paso más allá. 😎

Guardando el resultado en un archivo.

Aunque ya tengamos el resultado deseado en una “variable” supongamos que estamos creando un robot (o bot como los mientan ahora en este siglo) y queremos guardar el resultado en un archivo ¿qué tiene que ver PHP curl con esto si ya sabemos el lenguaje PHP y sabemos como hacerlo aparte?

Pues resulta que con CURLOPT_FILE en curl_setopt() permite guardarlo en un archivo, pero antes tenemos que abrir el archivo y pasarle la “referencia” a PHP curl:

<?php
  $objCurl = curl_init("http://www.soporteweb.com/");
  if ($objCurl == false) {
    print "No se pudo inicializar <b>PHP curl</b>.<br>";
  } else {
    $nom_arch = 'PHP_curl.html';
    $arch = fopen( $nom_arch , "w");
    if ($arch == false ) {
      print "No se pudo abrir el archivo '".$nom_arch."'<br>";
      curl_close ($objCurl);
    } else {
      $resp = curl_setopt ($objCurl, CURLOPT_RETURNTRANSFER, 1);
      if ( $resp == false ) {
        print "No se pudo establecer CURLOPT_RETURNTRANSFER.<br>";
        curl_close ($objCurl);
      } else {
        $resp = curl_setopt ($objCurl, CURLOPT_FILE, $arch);
        if ( $resp == false ) {
          print "No se pudo establecer CURLOPT_FILE.<br>";
          curl_close ($objCurl);
      } else {
          $resul = curl_exec ($objCurl);
          if ($resul == false) {
            echo "No se pudo ejecutar PHP curl.<br>";
          } else {
            print "El archivo fue guardado con el nombre 'PHP_curl.html'.<br>";
            // curl_close NO devuelve resultado:
            curl_close ($objCurl);
          }
        }
      }
    }
  }
?>

Si tenéis problemas para escribir el archivo en disco REVISAD vuestros derechos de escritura para PHP especialmente para el grupo “www-data”.

Así de sencillo, con las correspondientes rutinas de depuración para nosotros. Como tal vez se vea un poco largo hemos coloreado las partes importantes para que sigáis el hilo. ¿Que por qué nos hemos ido por la negación siempre de primero? Pues revisando la función fopen() verificamos que si es exitosa devuelve una referencia al archivo más no un valor de tipo booleno -verdadero-. En cambio si falla la función siempre devuelve un valor boleano falso. Lo de seguir usando la negación por defecto es para llevar el mismo estilo parejo al resto del código.

Mejorando la claridad de la sintaxis con ayuda de exit().

Una función “vieja” en PHP es la función die() que es totalmente equivalente a exit() que es más “elegante”. El chiste del asunto es emplear la conjunción or (operador lógico “o”) para unir la acción que queremos realizar con la función exit(). Dicha función permite como parámetro una cadena de texto o un entero entre cero y 254 (el 255 está reservado para uso exclusivo de PHP). Nos gusta mejor la opción de pasarle una cadena de texto con el mensaje que queremos presentar al usuario ¡o a nosotros mismos!

Otro punto importante es que la función exit() aparte de mostrar mensaje y cerrar adecuadamente los objetos en memoria es que sale inmediatamente y no ejecuta el resto de las líneas que quedan a partir de su llamada.

Veamos entonces cómo emplearlo en nuestra labor que hoy nos ocupa (para no alargar tanto cada línea fijaos el uso del punto y coma para separar bloques de código multilíneas):

<?php
  $objCurl = curl_init("http://www.soporteweb.com/")
    or exit("No se pudo inicializar <b>PHP curl</b>.<br>");

  $nom_arch = 'PHP_curl.html';
  $arch = fopen( $nom_arch , "w")
    or exit("No se pudo abrir el archivo '".$nom_arch."'<br>");

  curl_setopt ($objCurl, CURLOPT_RETURNTRANSFER, 1)
    or exit("No se pudo establecer CURLOPT_RETURNTRANSFER.<br>");

  curl_setopt ($objCurl, CURLOPT_FILE, $arch)
    or exit("No se pudo establecer CURLOPT_FILE.<br>");

  curl_exec ($objCurl)
    or exit("No se pudo ejecutar PHP curl.<br>");

  print "El archivo fue guardado con el nombre 'PHP_curl.html'.<br>";

  // curl_close NO devuelve resultado:
  curl_close ($objCurl);
?>

¡Qué gran mejora en la legibilidad! Debemos aclarar que exit() de manera implícita llama a los procedimientos de cierre y liberación de recursos de memoria (destructor lo nombran en lenguaje C++) así que como ven es una vía muy pragmática para nuestros propósitos.

Si queréis probar como funciona la rutina con control de excepciones, colocad una dirección web que no exista y mirad que sucede, ¡experimentad! También os recomendamos probar otros protocolos, por ejemplo FTP en un servidor público como por ejemplo “ftp://ftp.cesca.es/” donde veremos un listado de archivos disponibles para ser descargados.

Probando otros protocolos: FTP.

En el párrafo anterior os sugerimos probar el protocolo FTP y no hubo nada que cambiar en el código que teníamos -aparte de la URL, por supuesto-. Pero PHP curl tiene sus opciones y a continuación pasamos a revisar alguna de ellas. La primera que revisaremos limita el listado obtenido de archivos y directorios, osea, no muestra los permisos de cada uno de ellos. La sintaxis en el comando curl_setopt() -y todas las opciones utilizan esta función- es la siguiente:


1
2
curl_setopt($objCurl, <span style="color: #008000;">CURLOPT_FTPLISTONLY</span>, 1)
  or exit("No se pudo establecer CURLOPT_FTPLISTONLY");

Si el servidor FTP no fuera público o exigiera una conexión tipo anónimo usaremos esto:

 curl_setopt($objCurl, CURLOPT_USERPWD, "anonimo:su@correo-e.com")
    or exit("No se pudo establecer CURLOPT_USERPWD");

Con esta novedad de introducir credenciales de conexión nos encontramos con otro tipo de manejo de excepciones: dado el caso las credenciales no funcionen (mala escritura, contraseña vencida, usuario inexistente, etc) dentro del obejto PHP curl se guardará en una instancia aparte el resultado del intento de conexión, para ellos contamos con:

 echo curl_error($objCurl);

Pasando valores por medio del método POST.

Finalmente llegamos al meollo del asunto: poder pasar a un servidor web una o más variables por medio del método POST a un servidor web. Para propósitos de aprendizaje diremos que es uno de los métodos más populares debido a su cierta privacidad ya que el usuario no puede ver el enlace como en el método GET y tampoco es “cacheable” por los navegadores web.

Primero haremos una rchivo que nos muestre todas las variables que reciba y las liste por pantalla, de manera increíble solo necesita una sola líneas de código (guardar con el nombre de “curl_post.php“):

<?php
  var_dump($_POST);
?>

Una vez tengamos este archivo ya sea en nuestro servidor local o en nuestro servidor remoto podremos comenzar a escribir el siguiente script:

<?php
 $objCurl = curl_init("http://localhost/curl_post.php")
 or exit("No se pudo inicializar PHP curl<br>");

 curl_setopt($objCurl, CURLOPT_POST, 1)
 or exit("No se pudo establecer CURLOPT_POST");

 //Pasamos las variables que nos interesan al servidor
 curl_setopt($objCurl, CURLOPT_POSTFIELDS, "var1=uno&var2=dos&var3=tres")
 or exit("No se pudieron establecer las variables en CURLOPT_POSTFIELDS");

 curl_exec ($objCurl)
 or exit("No se pudo ejecutar PHP curl.");

 curl_close ($curl);
?>

Debido a los mensaje que incluimos en cada exit() y con el coloreado del código no hay nada que explicar… excepto unas cuantas acotaciones:

  • Las variables que pasamos en el método POST deben estar por pares unidas con el ampersand y separadas por medio de un signo de igualdad.
  • Los espacios no se permiten, debemos pasar “%20” o mejor dicho debemos darle un formato especial antes de enviarlo. El comando que nos ayudará será urlencode() y para nosotros castellanohablantes es importante representar bien los acentos, etc.
 //Pasamos las variables que nos interesan al servidor
 $var_post = urlencode("var1=Venezuela&var2=América del Sur&var3=Güigüe");
 curl_setopt($objCurl, CURLOPT_POSTFIELDS, $var_post)
   or exit("No se pudieron establecer las variables en CURLOPT_POSTFIELDS");

Fuera de tema: “Tamper data for Mozilla Firefox”.

Adam Judson es un desarrollador que tiene -nos tiene- como usuarios a más de 80 mil personas en su trabajo de programación desde el año 2007. Él desarrolló “Tamper Data” para este popular navegador, una herramienta para, según sus propias palabras “pruebas de seguridad en aplicaciones web por medio de la modificación de los parámetros POST”.

Dicha herramienta la podemos instalar en nuestro navegador (requiere reinicio del navegador y no es compatible con “Google Web Accelerator”) y con ella podremos visitar cualquier sitio web que utilize envio de datos POST y al activarlo en una ventana aparte mostrará sin molestar ni influir en nada el tráfico saliente de nuestro ordenador por medio de nuestro navegador web Firefox. ¿Por qué anuncia pruebas de seguridad? Porque nosotros muy bien sabemos como programadores que el código fuente de nuestras aplicaciones web están a la vista de los usuarios ¿pero que tal lo que no se ve? Pues acá entra “Tamper Data”: por más que coloquemos validación HTML5 y JavaScript del lado del cliente, si no utilizamos HTTPS el tráfico entre el usuario y nuestro servidor puede ser modificado por terceros. Y aunque si usaramos HTTPS tampoco podemos confiarnos de nuestros usuarios, verbigracia la misma herramienta que estamos recomendando puede modificar los datos si en la venta que se nos abre hacemos click en “modificar”. Al activar este botón, cuando sale algo de nuestro ordenador nos pregunta si deseamos modificar algún dato, ¡y allí podremos echar por tierra toda la hermosa programación hecha en HTML5 y javaScript!

Este comentario es “fuera de tema”: para combatir esto último lo que debemos hacer es, en lenguaje PHP -o vuestro lenguaje utilizado- volver a validar los datos recibidos desde el usuario, ¡PERO HAY MÁS! Es obligatorio agregar “disparadores” y “restricciones” incrustados en nuestra base de datos (recomendamos PostgreSQL por su capacidad de incluso aceptar guiones en lenguaje Python) para volver a validar datos al agregar los datos a nuestro motor informático. Más detalles escapan de esta entrada, pero este resumen es el mejor que podemos expresar al respecto.

Ejecutando PHP curl en modo de depuración.

“Verbose” en idioma inglés describe un modo de hablar más de lo necesario. Pero en nuestro mundo del software libre nuestra búsqueda del conocimiento es insaciable, “solo sabemos que no sabemos nada” por ello le dedicamos esta sección empinada a ahondar en PHP curl. Aparte de aprender más y mantener nuestro cerebro haciendo ejercicios, debido a la gran cantidad de protocolos y opciones es sumamente fácil para nosotros el cometer errores solicitando opciones inexistentes o incompatibles entre ellas, si son varios los parámetros que les pasemos.

Para activar el modo de depuración -vamos que la traducción al castellano de “verboso” no cuela- en PHP curl echamos mano de la alternativa CURLOPT_VERBOSE en la ya consabida función curl_opt() ¡pero esperen -como dice el “infomercial” de T.V.- hay más! PHP curl, dijimos, lo tenemos claro, emplea stdin y stdout que son los más conocidos pero también utiliza stderr ¡para algo que no es error, sino DEPURACIÓN! Teoricamente no debería ser pero en la práctica, el mundo real esto es de facto que lo hacen -y haremos-: capturar el stderr para llevar los mensajes de depuración hacia un archivo de escritura y de adición. Este archivo si no está creado, lo hace, y lo abre para agregar dichos datos y si existe le adiciona al final, de tal manera que llevamos una especie de bitácora para nuestro estudio y control.

<?php
  $ObjCurl = curl_init()
    or exit("No se pudo inicializar PHP curl.<br>");

  curl_setopt ($ObjCurl, CURLOPT_URL, "http://www.soporteweb.com")
    or exit("No se pudo establecer la URL.<br>");

  curl_setopt($ObjCurl, CURLOPT_VERBOSE, 1)
     or exit("No se pudo establecer el modo de depuración.<br>");

  $verbose_arch = fopen('verbose.txt', 'a');
  curl_setopt($ObjCurl, CURLOPT_STDERR, $verbose_arch)
    or exit("No se pudo establecer CURLOPT_STDERR<br>.");

  curl_exec ($ObjCurl)
    or exit("No se pudo ejecutar PHP curl.<br>");

  curl_close ($ObjCurl);
?>

Y veremos algo parecido a esto:

CURLOPT_VERBOSE
CURLOPT_VERBOSE

Explicamos que:

  • Las líneas que comienza con un asterisco son mensajes informativos de PHP curl.
  • Las líneas que comienzan con “>” es información que se le envia al servidor web, ftp, etc.
  • Las líneas que comienzan con “<” es la información que recibimos de tal servidor.
  • Los servidores web basados en ASP.NET devolverán un error “HTTP/1.1 500 Internal Server Error” y no podremos hacer nada ya que no se rigen por las normas comunes basadas en RFC y recomendaciones de WWW.

Otros usos para PHP curl.

Por nuestros experimentos vimos que PHP curl permite grabar en archivos “flujos de datos” de una manera básica, sin estar amarrado a protocolos (si lo usamos con FTP veremos que nos hacen falta los comandos populares y que solo podremos usar si tenemos un cliente FTP como tal). Eso deja abierta la posiblidad a darle infinidad de usos sin siquiera saber -ni preocuparnos- “con quien estamos hablando”. Un ejemplo de ello es con el acceso a servidores con tecnología ASP.NET o la mismisa consulta de nuestra dirección IP que devuelve un resultado no normalizado ni con metadato alguno (solo nosotros, seres humanos, estamos con la plena certeza que es una dirección IPv4).

Por ejemplo, si en vez de usar soporteweb.com para retribuir nuestra dirección IPv4 usamos el servicio que presta icanhazip.com en el modo de depuración veremos algo como esto:

icanhazip.com Get the facts
icanhazip.com Get the facts

Y al seguir el enlace indicado abrimos el blog de Major Hayden (sí, ese es el nombre, no no es mayor de ningún ejército ni alcalde de ninguna ciudad) un administrador de sistemas GNU/Linux con 6 años de experiencia quien ha tenido excelentes maestros y está dispuesto siempre aprender… como nosotros mismos, quienes escribimos y quienes leemos este humilde sitio web.

Auguramos que curl y PH curl seguirá creciendo y mejorando para nuestro beneplácito y que nosotros, a la larga, algún día aportaremos nuestro granito de arena a la causa del software libre, de una u otra manera, de manera inexorable.

curl_setopt(): parámetros mas socorridos.

La lista es larga en verdad pero mencionaremos, al menos, los que avizoramos de alguna utilidad dada la experiencia que hemos logrado a lo largo de los años:

CURLOPT_USERAGENT

Con esta opción podremos indicarle al servidor con el cual le estamos requiriendo información acerca de nuestra identidad. Curiosamente PHP curl por defecto no envía indentificación alguna acerca del nombre del software pero es que también el servidor que atiende la consulta tampoco la requiere como obligatoria. En la práctica les mostramos (las direcciones IP las ocultamos -junto con otros detalles- de las visitas a esta vuestra página web):

PHP curl no se identifica -por defecto-
PHP curl no se identifica -por defecto-

Así que le aplicamos código y así quedaría la visita de nuestro bot en cierne:

Usando PHP curl CURLOPT_USERAGENT
Usando PHP curl CURLOPT_USERAGENT

CURLOPT_CONNECTTIMEOUT

A veces estimamos en cuánto tiempo debería responder determinado proceso y si no se realiza pues no está bien afinado nuestro servidor no sin antes descartar fallas de internet, etc. Para ello CURLOPT_CONNECTTIMEOUT es el idóneo para que nuestro script no se cuelgue indefinidamente, al cabo de cierto tiempo que le establezcamos y si no logra conectar con el servidor la tarea finalizará. El tercer parámetro que pasaríamos a continuación es el número de segundos, lo cual es una eternidad en tiempo de computadores, por ello también contamos con CURLOPT_CONNECTIONTIMEOUT_MS que viene expresado en milisegundos si estamos realmente apurados.

Es una excelente opción para desarrollar herramientas de diagnóstico a equipos remotos y podremos llevar un ergistro de eventos en nuestra base de datos (sí, que ya hay mucho software para eso pero también hay tareas tan pequeñas que no necesitamos “una mandarria sino un simple martillito”)

CURLOPT_COOKIE y CURLOPT_COOKIEFILE

Una “cookie” en inglés o galletita en castellano, es una pieza de información que plantan los servidores web en nuestros navegadores para identificarnos de manera absoluta. Al igual que el método POST debemos saber el nombre de la galletita y por ende su contenido, así que no la generamos nosotros -obvio- pero si debemos tener una para poder obtener respuesta de algunos servidores, quienes comparan si tienen la galletita en su lista de memoria (las galletitas tienen vencimiento o validez en el tiempo) y así podrán:

  • bien sea aceptar nuestra petición ó
  • incluso devolvernos unos valores personalizados.

De allí viene el gran temor a la violación de nuestra privacidad, una delgada línea demarca las buenas de las malas intenciones.

De esto último viene la necesidad de CURLOPT_COOKIEFILE, muchas veces son tantas las galletitas usadas por nosotros los programadores que mejor es enviar un archivo completo con ellas incluídas. Aquí debemos colocar el nombre del archivo en la opción anterior debemos enviar los valores en sí.

Otra manera de pasar una gran cantidad de galletitas es pasar el jarrón completo, un fichero, y para que no se nos olvide la sintaxis le pusieron el curioso nombre CURLOPT_COOKIEJAR. Un ejemplo sería:

curl_setopt($objCurl, CURLOPT_COOKIEJAR, 'jarron_de_galletitas.txt');

1
CURLOPT_SSL_VERIFYPEER

Con esta opción podemos deshabilitar que verifique certificados en una conexión https (o mejor dicho TLS). Esto normalmente está habilitado pero uno a veces necesita, por economía, un certificado autofirmado el cual no está validado ante ningún tercer ente. Con esta opción cambiada a false en el tercer parámetro evitaremos este problemita.

1
CURLOPT_FOLLOWLOCATION

Actualmente las redirecciones de página se ha vuelto el pan nuestro de cada día motivado a la popularidad de las páginas web. Una página de cualquier gobierno del mundo de muy seguro que tendrá miles y hasta millones de visitantes y como comprenderán un solo servidor web jamás ni nunca se daría abasto. Lo que se ha inventado es poner granjas de servidores en distintas partes del mundo con copias constantes de los dominios deseados y redireccionado el tráfico con ayuda de potentes DNS: todo esto se conoce como CDN o “Content Delivery Network”.

La idea del asunto es que cuando uno solicita una página web los DNS encargados redireccionan nuestra solicitud a la granja de servidores más cerca a nosotros de manera geográfica donde habrá una copia de la web que queremos. ¿A qué viene todo este cuento con PHP curl? Que es muy probable que la respuesta que obtengamos será una cabecera tipo 300 indicandonos que la direcciíon adecuadad para nosotros y entonces volvemos a hacer la petición -la misma petición- pero a otro servidor más cercano (o mas desocupado, o que tenga nuestra idioma, etc. -el que nos convenga-).

PHP curl ya está preparado en ese escenario y estableceremos CURLOPT_FOLLOWLOCATION a verdadero y por defecto PHP curl redireccionará hasta un máximo de 5 oportunidades nuestra solicitud (más adelante veremos otra función que nos dirá cuántas redirecciones siguió con la variable CURLINFO_REDIRECT_COUNT establecida).

Un problema se presenta al hacer una consulta POST: después del primer redireccionamiento PHP curl NO HACE una consulta POST sino una consulta GET (por razones históricas y de costumbres en los navegadores) y esto es un problema porque son métodos distintos y no obtendremos respuesta (aparte de que nos volveremos “locos” buscando dónde está el error). Para prevenir este inconveniente en vez de fijar CURLOPT_POST a “true” tomaremos otra opción, CURLOPT_CUSTOMREQUEST fijado a “POST”:

curl_setopt($ObjCurl, CURLOPT_CUSTOMREQUEST, "POST");

Otra advertencia más: cuando uno sube archivos por medio de CURLOPT_POSTFIELDS en la segunda redirección no será enviado dicho fichero. También para prevenir esto urge emplear CURLOPT_POSTREDIR fijado el valor a 3 para que maneje los redireccionamientos 301 y 302 reenviando el archivo en cada oportunidad (es más tráfico de datos pero ¿cómo hacemos con los CDN’s que llegaron para quedarse?).

Panorama general del resto de las opciones de curl_setopt()

Ya en este punto os habreis dado cuenta de la importancia de esta función, recordad que solo hemos visto apenas cuatro que van en este orden: curl_init(), curl_setopt(), curl_exec() y curl_close(); pues bien hay 23 funciones más de las cuales más adelante estudiaremos una de ellas (por ahora).

He aquí un listado clasificado por el tipo de contenido que hay que pasar en el tercer parámetro de curl_setopt(), de un vistazo (en marrón las que hemos visto y analizado):

Aquellas cuyo valor debe ser booleano (verdadero<>0 ó falso=0):
  • CURLOPT_AUTOREFERER
  • CURLOPT_BINARYTRANSFER
  • CURLOPT_COOKIESESSION
  • CURLOPT_CERTINFO
  • CURLOPT_CONNECT_ONLY
  • CURLOPT_CRLF
  • CURLOPT_DNS_USE_GLOBAL_CACHE
  • CURLOPT_FAILONERROR
  • CURLOPT_SSL_FALSESTART
  • CURLOPT_FILETIME
  • CURLOPT_FOLLOWLOCATION
  • CURLOPT_FORBID_REUSE
  • CURLOPT_FRESH_CONNECT
  • CURLOPT_FTP_USE_EPRT
  • CURLOPT_FTP_USE_EPSV
  • CURLOPT_FTP_CREATE_MISSING_DIRS
  • CURLOPT_FTPAPPEND
  • CURLOPT_TCP_NODELAY
  • CURLOPT_FTPASCII
  • CURLOPT_FTPLISTONLY
  • CURLOPT_HEADER
  • CURLINFO_HEADER_OUT
  • CURLOPT_HTTPGET
  • CURLOPT_HTTPPROXYTUNNEL
  • CURLOPT_MUTE
  • CURLOPT_NETRC
  • CURLOPT_NOBODY
  • CURLOPT_NOPROGRESS
  • CURLOPT_NOSIGNAL
  • CURLOPT_PATH_AS_IS
  • CURLOPT_PIPEWAIT
  • CURLOPT_POST
  • CURLOPT_PUT
  • CURLOPT_RETURNTRANSFER
  • CURLOPT_SAFE_UPLOAD
  • CURLOPT_SASL_IR
  • CURLOPT_SSL_ENABLE_ALPN
  • CURLOPT_SSL_ENABLE_NPN
  • CURLOPT_SSL_VERIFYPEER
  • CURLOPT_SSL_VERIFYSTATUS
  • CURLOPT_TCP_FASTOPEN
  • CURLOPT_TFTP_NO_OPTIONS
  • CURLOPT_TRANSFERTEXT
  • CURLOPT_UNRESTRICTED_AUTH
  • CURLOPT_UPLOAD
  • CURLOPT_VERBOSE
Aquellas cuyo valor debe ser numérico entero:
  • CURLOPT_BUFFERSIZE
  • CURLOPT_CLOSEPOLICY
  • CURLOPT_CONNECTTIMEOUT
  • CURLOPT_CONNECTTIMEOUT_MS
  • CURLOPT_DNS_CACHE_TIMEOUT
  • CURLOPT_EXPECT_100_TIMEOUT_MS
  • CURLOPT_FTPSSLAUTH
  • CURLOPT_HEADEROPT
  • CURLOPT_HTTP_VERSION
  • CURLOPT_HTTPAUTH
  • CURLOPT_INFILESIZE
  • CURLOPT_LOW_SPEED_LIMIT
  • CURLOPT_LOW_SPEED_TIME
  • CURLOPT_MAXCONNECTS
  • CURLOPT_MAXREDIRS
  • CURLOPT_PORT
  • CURLOPT_POSTREDIR
  • CURLOPT_PROTOCOLS
    • CURLPROTO_HTTP, CURLPROTO_HTTPS, CURLPROTO_FTP, CURLPROTO_FTPS, CURLPROTO_SCP, CURLPROTO_SFTP, CURLPROTO_TELNET, CURLPROTO_LDAP, CURLPROTO_LDAPS, CURLPROTO_DICT, CURLPROTO_FILE, CURLPROTO_TFTP, CURLPROTO_ALL
  • CURLOPT_PROXYAUTH
  • CURLOPT_PROXYPORT
  • CURLOPT_PROXYTYPE
  • CURLOPT_REDIR_PROTOCOLS
  • CURLOPT_RESUME_FROM
  • CURLOPT_SSL_OPTIONS
  • CURLOPT_SSL_VERIFYHOST
  • CURLOPT_SSLVERSION
  • CURLOPT_STREAM_WEIGHT
  • CURLOPT_TIMECONDITION
  • CURLOPT_TIMEOUT
  • CURLOPT_TIMEOUT_MS
  • CURLOPT_TIMEVALUE
  • CURLOPT_MAX_RECV_SPEED_LARGE
  • CURLOPT_MAX_SEND_SPEED_LARGE
  • CURLOPT_SSH_AUTH_TYPES
  • CURLOPT_IPRESOLVE
    • CURL_IPRESOLVE_WHATEVER (por defecto), CURL_IPRESOLVE_V4, CURL_IPRESOLVE_V6
  • CURLOPT_FTP_FILEMETHOD
    • CURLFTPMETHOD_MULTICWD, CURLFTPMETHOD_NOCWD, CURLFTPMETHOD_SINGLECWD.
Aquellas cuyo valor debe ser una cadena de texto:
  • CURLOPT_CAINFO
  • CURLOPT_CAPATH
  • CURLOPT_COOKIE
  • CURLOPT_COOKIEFILE
  • CURLOPT_COOKIEJAR
  • CURLOPT_CUSTOMREQUEST
  • CURLOPT_DEFAULT_PROTOCOL
  • CURLOPT_DNS_INTERFACE
  • CURLOPT_DNS_LOCAL_IP4
  • CURLOPT_DNS_LOCAL_IP6
  • CURLOPT_EGDSOCKET
  • CURLOPT_ENCODING
  • CURLOPT_FTPPORT
  • CURLOPT_INTERFACE
  • CURLOPT_KEYPASSWD
  • CURLOPT_KRB4LEVEL
  • CURLOPT_LOGIN_OPTIONS
  • CURLOPT_PINNEDPUBLICKEY
  • CURLOPT_POSTFIELDS
  • CURLOPT_PRIVATE
  • CURLOPT_PROXY
  • CURLOPT_PROXY_SERVICE_NAME
  • CURLOPT_PROXYUSERPWD
  • CURLOPT_RANDOM_FILE
  • CURLOPT_RANGE
  • CURLOPT_REFERER
  • CURLOPT_SERVICE_NAME
  • CURLOPT_SSH_HOST_PUBLIC_KEY_MD5
  • CURLOPT_SSH_PUBLIC_KEYFILE
  • CURLOPT_SSH_PRIVATE_KEYFILE
  • CURLOPT_SSL_CIPHER_LIST
  • CURLOPT_SSLCERT
  • CURLOPT_SSLCERTPASSWD
  • CURLOPT_SSLCERTTYPE
  • CURLOPT_SSLENGINE
  • CURLOPT_SSLENGINE_DEFAULT
  • CURLOPT_SSLKEY
  • CURLOPT_SSLKEYPASSWD
  • CURLOPT_SSLKEYTYPE
  • CURLOPT_UNIX_SOCKET_PATH
  • CURLOPT_URL
  • CURLOPT_USERAGENT
  • CURLOPT_USERNAME
  • CURLOPT_USERPWD
  • CURLOPT_XOAUTH2_BEARER
Aquellas cuyo valor debe ser una matriz:
  • CURLOPT_CONNECT_TO
  • CURLOPT_HTTP200ALIASES
  • CURLOPT_HTTPHEADER
  • CURLOPT_POSTQUOTE
  • CURLOPT_PROXYHEADER
  • CURLOPT_QUOTE
Aquellas cuyo valor debe ser un recurso de flujo de datos:
  • CURLOPT_FILE
  • CURLOPT_INFILE
  • CURLOPT_STDERR
  • CURLOPT_WRITEHEADER
Aquellas cuyo valor debe ser una función o una función de cierre:
  • CURLOPT_HEADERFUNCTION
  • CURLOPT_PASSWDFUNCTION
  • CURLOPT_PROGRESSFUNCTION
  • CURLOPT_READFUNCTION
  • CURLOPT_WRITEFUNCTION
Aquellas cuyo valor debe ser una muy específica:
  • CURLOPT_SHARE

Función curl_setopt_array.

Nos dimos cuenta como la función exit() mejoró muy bien la legilibilidad de nuestro código y además proporciona información a nuestros usuarios en caso de tratamiento de excepciones. Pero hay una manera aún mejor de configurar las opciones justo antes de ejecutar curl_exec() con el detalle que es como la famosa película de vaqueros: tiene lo bueno, lo malo y lo feo pero sin lo feo. Lo bueno -y muy bueno- es que como dijimos mejora la apariencia de nuestro código y abre nuevas posibilidades con el uso de una matriz: podemos realizar una función que consulte una base de datos y llene dicha matriz. Lo malo es que al pasar todo de un solo golpe a la unficón ésta acepta todo o no acepta nada y tendremos nuestra bella salida diciendo “no se pudo establecer culr_setopt_arraypero no nos indicará dónde, cuál es el elemento que falla.

<?php
  $objCurl = curl_init()
    or exit("No se pudo inicializar PHP curl.<br>");

  $verbose = fopen('verbose.txt', 'a')
    or exit("No se pudo abrir el archivo verbose.txt<br>");
  $opciones = array(
                    CURLOPT_URL     => 'https://icanhazip.com',
                    CURLOPT_VERBOSE => 1,
                    CURLOPT_STDERR  => $verbose
                    );

  curl_setopt_array($objCurl, $opciones)
    or exit("No se pudo establecer curl_setopt_array()");

  curl_exec ($objCurl)
    or exit("No se pudo ejecutar PHP curl.<br>");

  curl_close ($objCurl);
?>

Percataos que colocamos el URL en la matriz para abultar y activamos el modo de depuración de resto todo lo demás es el mismo ejemplo que colocamos anteriormente. Lo curioso del asunto es que curl_setopt() y curl_setopt_array() pueden trabajar juntos perfectamente, lo anterior lo podemos reescribir como lo próximo y funciona plenamente:

<?php
  $objCurl = curl_init()
    or exit("No se pudo inicializar PHP curl.<br>");

  curl_setopt($objCurl, CURLOPT_URL ,'https://icanhazip.com')
    or exit("No se pudo establecer el CULROPT_URL");


  $verbose = fopen('verbose.txt', 'a')
    or exit("No se pudo abrir el archivo verbose.txt<br>");
  $opciones = array(
                    CURLOPT_VERBOSE => 1,
                    CURLOPT_STDERR  => $verbose
                    );

  curl_setopt_array($objCurl, $opciones)
    or exit("No se pudo establecer curl_setopt_array()");

  curl_exec ($objCurl)
    or exit("No se pudo ejecutar PHP curl.<br>");

  curl_close ($objCurl);
?>

Analizando los resultados de la última conexión.

Comentamos que PHP curl puede utilizarse para fabricar una sencilla herramienta de monitoreo de servidores. Pensando en esto indagamos en ciertas opciones que trae la librería y de la cual podemos obtener gran cantidad de información, siempre pensando en guardarlo en una base de datos para su posterior análisis de manera masiva. Pero debemos comenzar por lo básico y no irnos precipitadamente.

Aparte de las opciones de depuración, que ya logramos vertirlas en un archivo que llamamos simplemente “verbose.txt” (y cuyo nombre podemos cambiar a la fecha y hora actual para que siempre sea un archivo distinto y almacenar -o borrar, o procesar, etc.- cuando queramos) podemos echar mano de otra función para obtener los datos de la conexión. Tal función es denominada curl_getinfo() a la que introducimos nuestro manejador creado por curl_init().

Esta función devuelve falso si no tiene información o una matriz con elementos predefinidos -no todos-. Para poder escribir esta matriz en un archivo agarramos a la función serialize() para convertirla en una cadena de texto antes de guardarla.

De una vez vamos a la práctica con el primer ejemplo que presentamos, el más “refinado” con las llamadas exit() ¿lo recordais? Pero vamos un paso adelante y lo modificamos, primero para que tome la URL por el método GET: escribimos en la barra de direcciones la ubicación de nuestro guion y al final agregamos un signo de cierre de interrogante con la palabra “url”, luego un signo de igualdad y a continuación el dominio o página que queremos descargar y guardar -para luego analizar según el propósito que tengamos, que para cada persona es muy variopinto. Supongamos que nuestro guion está en nuestro servidor local y se llama “curl.php”, el llamado sería el siguiente (obvien el prefijo “http://” porque lo agregamos en el script):

http://localhost/curl.php?url=www.ks7000.net.ve

También agregaremos dos mensajes adicionales: si no se pasa una URL entonces alerta que debe pasar una y otro mensaje para indicar que ha sido guardada en un archivo (recordad que usamos la opcion CURLOPT_RETURNTRANSFER al valor de 1). Coloreamos el código para su mayor comprensión:

<?php
if ($_GET["url"])
{
 $objCurl = curl_init("http://".$_GET["url"])
 or exit("No se pudo inicializar PHP curl.<br />");

 $nom_arch = 'servidor.html';
 $arch = fopen( $nom_arch , "a")
 or exit("No se pudo abrir el archivo '".$nom_arch."'<br />");

 curl_setopt ($objCurl, CURLOPT_RETURNTRANSFER, 1)
 or exit("No se pudo establecer CURLOPT_RETURNTRANSFER.<br />");

 curl_setopt ($objCurl, CURLOPT_FILE, $arch)
   or exit("No se pudo establecer CURLOPT_FILE.<br />");

 curl_setopt ($objCurl, CURLOPT_CONNECTTIMEOUT, 7)
   or exit("No se pudo establecer CURLOPT_CONNECTTIMEOUT.<br />");
 curl_exec ($objCurl)
 or exit("No se pudo ejecutar PHP curl.<br />");

 $nom_arch = "servidor_respuesta.txt";
 $archivo = fopen($nom_arch, "a")
 or exit("No se pudo abrir el archivo'".$nom_arch."'<br />");

 $resp = curl_getinfo($objCurl)
 or exit("No se pudo obtener información de la ultima conexion.<br />");

 fwrite($archivo, serialize($resp))
 or exit("No se pudo escribir en el archivo '".$nom_arch."'<br />");

 fclose($archivo)
 or exit("No se pudo cerrar el archivo '".$nom_arch."'<br />");

 // curl_close NO devuelve resultado:
 curl_close ($objCurl);
 echo "URL descargada y guardada.<br />";
} else {
 echo "Debe pasar una URL para ser descargada y analizada.<br />";
}
?>

Es crucial llamar esta función ANTES de llamar la función curl_close() que es cuando aún existe el objeto en memoria.

Matrix con campos predefinidos.

Esos datos que guardamos en el anterior software que inventamos ya están seleccionados por los desarrolladores de PHP curl y son los siguientes (repetimos, NO son todos los disponibles):

  • “url”
  • “content_type”
  • “http_code”
  • “header_size”
  • “request_size”
  • “filetime”
  • “ssl_verify_result”
  • “redirect_count”
  • “total_time”
  • “namelookup_time”
  • “connect_time”
  • “pretransfer_time”
  • “size_upload”
  • “size_download”
  • “speed_download”
  • “speed_upload”
  • “download_content_length”
  • “upload_content_length”
  • “starttransfer_time”
  • “redirect_time”
  • “certinfo”
  • “primary_ip”
  • “primary_port”
  • “local_ip”
  • “local_port”
  • “redirect_url”
  • “request_header” (solamente está definido si CURLINFO_HEADER_OUT está establecido por una llamada previa a curl_setopt())

Totalidad de los campos de get_info()

Podemos solicitar cualquiera de estos campos pasando como parámetro los siguientes valores a la función curl_getinfo() -con una breve descripción y ordenados alfabéticamente-:

  • CURLINFO_APPCONNECT_TIME – Tiempo, en segundos, desde el inicio hasta la conexión/apretón de manos SSL/SSH del host remoto.
  • CURLINFO_CERTINFO – Serie de certificados TLS.
  • CURLINFO_CONDITION_UNMET – Información del condicional de timepo unmet.
  • CURLINFO_CONNECT_TIME – Tiempo, en segundos, que tomó el establecimiento de la conexión.
  • CURLINFO_CONTENT_LENGTH_DOWNLOAD – Logitud del contenido de la descarga, leída desde el campo “Content-Length:”.
  • CURLINFO_CONTENT_LENGTH_UPLOAD – Tamaño especificado de subida .
  • CURLINFO_CONTENT_TYPE – “Content-Type:” del documento solicitado. NULL indica que el servidor no envío un encabezado “Content-Type:” válido.
  • CURLINFO_COOKIELIST – Todas las cookies conocidas.
  • CURLINFO_EFFECTIVE_URL – Último URL efectivo.
  • CURLINFO_FILETIME – Hora del documento remoto obtenido; si devuelve -1, la hora del documento es desconocida.
  • CURLINFO_FTP_ENTRY_PATH – Ruta de entrada en el servidor FTP.
  • CURLINFO_HEADER_OUT – El string de la petición enviada. Para que funcione, se ha de añadir la opción CURLINFO_HEADER_OUT al manejador, llamando a curl_setopt()
  • CURLINFO_HEADER_SIZE – Tamaño total de los encabezados recibidos.
  • CURLINFO_HTTP_CODE – Último código HTTP recibido.
  • CURLINFO_HTTP_CONNECTCODE – El código de respuesta de CONNECT.
  • CURLINFO_HTTPAUTH_AVAIL – Máscara de bits que indica el/los método/s de autenticación disponible/s de acuerdo a la respuesta anterior.
  • CURLINFO_LOCAL_IP – Dirección IP local (fuente) de la conexión más reciente.
  • CURLINFO_LOCAL_PORT – Puerto local (fuente) de la conexión más reciente.
  • CURLINFO_NAMELOOKUP_TIME – Tiempo, en segundos, en resolver el nombre.
  • CURLINFO_NUM_CONNECTS – Número de conexiones que curl ha tenido que crear para lograr la transferencia anterior.
  • CURLINFO_OS_ERRNO – Número de error (errno) de un fallo de conexion. Es número es específico de cada SO y sistema.
  • CURLINFO_PRETRANSFER_TIME – Tiempo, en segundos, desde el inicio hasta justo antes de que comience la transferencia del fichero.
  • CURLINFO_PRIMARY_IP – Dirección IP de la conexión más reciente.
  • CURLINFO_PRIMARY_PORT – Puerto de destino de la conexión más reciente.
  • CURLINFO_PRIVATE – Datos privados asociados a este manejador de cURL, previamente establecidos con la opción CURLOPT_PRIVATE de curl_setopt()
  • CURLINFO_PROXYAUTH_AVAIL – Máscara de bits que indica el/los método/s de autenticaición proxy disponible/s de acuerdo a la respuesta anterior.
  • CURLINFO_REDIRECT_COUNT – Número de redireccionamientos, con la opción CURLOPT_FOLLOWLOCATION habilitada.
  • CURLINFO_REDIRECT_TIME – Tiempo, en segundos, de todos los pasos de redireción antes de que la última transación haya empezado, con la opción CURLOPT_FOLLOWLOCATION habilitada.
  • CURLINFO_REDIRECT_URL – Con la opción CURLOPT_FOLLOWLOCATION inhabilitada: URL de redirección encontrado en la última transacción, que debería ser solicitado manualmente luego. Con la opción CURLOPT_FOLLOWLOCATION habilitada: está vacío. El URL de redirección en este caso está disponible en CURLINFO_EFFECTIVE_URL
  • CURLINFO_REQUEST_SIZE – Tamaño total de las peticiones realizadas, actualmente solo para peticiones HTTP.
  • CURLINFO_RESPONSE_CODE – El último código de respuesta.
  • CURLINFO_RTSP_CLIENT_CSEQ – Siguiente CSeq cliente de RTSP.
  • CURLINFO_RTSP_CSEQ_RECV – CSeq recivido recientemente.
  • CURLINFO_RTSP_SERVER_CSEQ – Siguiente CSeq servidor de RTSP.
  • CURLINFO_RTSP_SESSION_ID – ID de sesión de RTSP.
  • CURLINFO_SIZE_DOWNLOAD – Número total de bytes descargados.
  • CURLINFO_SIZE_UPLOAD – Número total de bytes subidos.
  • CURLINFO_SPEED_DOWNLOAD – Velocidad media de descarga.
  • CURLINFO_SPEED_UPLOAD – Velocidad media de subida.
  • CURLINFO_SSL_ENGINES – Criptomotores OpenSSL admitidos.
  • CURLINFO_SSL_VERIFYRESULT – Resultado de la verificación del certificado SSL solicitado por la opción CURLOPT_SSL_VERIFYPEER.
  • CURLINFO_STARTTRANSFER_TIME – Tiempo, en sengudos, hasta que el primer byte está a punto de transferirse.
  • CURLINFO_TOTAL_TIME – Duración total, en segundos, de última transferencia.

Resumen.

Recuerden lo que siempre dijo en vida nuestro Gran Maestro: “un punto, un punto y una línea recta“; aprovechen estos conocimientos para desarrollar programas y utilidades para fortalecer el Patrimonio Tecnológico de nuestra Humanidad no para escribir virus y gusanos que marguen las vidas de los demás.

<Eso es todo, por ahora>.

Fuentes consultadas.

En idioma castellano.

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:

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:

 

Historia de un viejo informático - eltamiz.com -

Mozilla Firefox Reader View.

Mozilla Firefox Reader View.

He de confesarles a todas y a todos que con el paso de los años mi vista se ha desmejorado; en el buen sentido que le damos por estos lares: “se me han quemado las pestañas”. Es por ello que con gusto he utilizado “Mozilla Firefox Reader View” el cual está explicado en buen castellano en este enlace. Aunque lo traducen como “Modo Lector” me gusta más “Modo de Lectura”, ya sabéis qué poético es nuestro idioma, así que visitadlo y volved para terminar de contaros la historia.


Un poco de historia.

Yo tengo poco tiempo disfrutando esta “extensión” del popular navegador ya que vino a estar disponible para computadoras desde enero de 2015, pero desde septiembre de 2012 se avizoraba y estaba disponible para la distribución Android, según leo en este artículo escrito en inglés.

Actualizado el viernes 26 de abril de 2016.

Este problema de la visualización de una página web, para poder complacer a la mayor cantidad de personas posibles, está bien descrito en una entrada del blog de Wardog un administrador de sistemas bien curtido en estas lides con los usuarios. Allí tenéis el tema con 74 comentarios (75  si me publican el que yo hice), si queréis leed que allí hay de todo (yquediostelopagueconunbuenRACAAAAA! estimado Wardog ja ja ja).

En mi ordenador portátil, corriendo Debian 7 a duras penas (antes le tenía Ubuntu 12 distro “perzonalizada” en hardware específico, pero Debian 7 trae todos los controladores por defecto) tengo Iceweasel y con el cual todos y todas sabemos que es quisquilloso con esto de la privacidad (más adelante explico con detalles de programación y lineas de código) y este modo NO viene activo por defecto. Buscando un poco en los foros de discusiones en Google observo que un problema parecido sucedía en la versión 38 y un usuario respondía al autor original de la discusión de una vez con una opción de configuración en about:config lo cual me dio una pista para lo que buscaba en Iceweasel y me produjo una segunda inquietud: ¿qué hace que se muestre el dichoso ícono de “modo de lectura” en unas páginas si y en otras no?

Vayamos por partes entonces, y comenzemos desde el principio. Estoy escribiendo un tutorial sobre HMTL5 -qué aún falta mucho para terminarlo- donde explico las características de esta versión “estrenada” a finales del 2014. Dicho artículo continuará con CSS “Cascading Style Sheets“, una forma de “dinamizar” las páginas web que yo sabía desde hace muchos años era el futuro de la web. Pues bien ese futuro es hoy, y me atrevo a decir que es el clavo que faltaba para terminar de fijar la tapa de la urna de los “webmaster” (sólo una autoridad como el sr. Jesús Lara se puede permitir publicar un artículo así, yo soy más bien de “vive y deja vivir” -eso sí, siempre y cuando no quebranten ninguna ley-).

El meollo del asunto.

Pues bien este “modo de lectura” hace uso intensivo del CSS, y específicamente la versión 3, que es modular y ha unificado cantidad de conceptos como <div>, <article>, <p>, etc. Volviendo al tema que dio inicio a esta entrada, este modo de lectura es 100% personalizable. ¡Y para qué será que la queremos personalizar! A mi en lo particular me encanta el justificado de párrafos, una cursilería, pero a otros usuarios si que le han dado uso útil y práctico: aprovechar el ancho total del monitor, que para estos días ya es una norma la relación 16:9 y no la 4:3 de los monitores tradicionales. Comentario aparte esta relación de aspecto 16:9 muestra las películas en su formato nativo y si el monitor le adaptamos un brazo giratorio es excelente para nosotros los programadores, ya que nuestro trabajo es a lo largo y no a lo ancho. Basado en este ultimo concepto es que el modo de lectura configura el ancho de los párrafos de manera corta, pero la buena combinación de fuente, color y color de fondo nos permite leer párrafos más anchos. Lo del tamaño de fuente en sus inicios (corrijanme si estoy equivocado) era un gran avance del Javascript hasta que se convirtió en norma en los navegadores web con la ya consabida combinación de {CTRL}+{+}, {CTRL}+{-} Y {CTRL}+{0} para volver a colocar la página que estamos visualizando a su tamaño “normal”, la que el programador consideró pertinente al montar la página.

Y en este punto volvemos al tema de los webmaster: tanto esfuerzo de los programadores, diseñadores, etc (los que le dan “arte” a la página con imágenes, colores y fuentes), tanto trabajo que invirtieron y que se esmeraron por nosotros y venimos y la colocamos en modo lectura dando al porro con todo.Cosas veredes Sancho.

Aprovechando las pocas vacaciones de diciembre -que aunque no lo creaís, trabajo, y para varios empresas- me dio por releer, DEGUSTAR de nuevo las “Memorias de un viejo informático” pero bien descansado con la portátil, que ya paso mucho tiempo sentado en los escritorios.

Historia de un viejo informático - eltamiz.com -
Historia de un viejo informático – eltamiz.com –

Pero el Iceweasel no trae activo el modo de lectura, ya que el código de dicho complemento “se reporta” con Google y eso viola la privacidad de los usuarios. Para los que se preocupan por esto, pues bueno a buscar el código fuente, modificarlo y distribuirlo según las licencias que a tal efecto tenga el dichoso software tan útil -al menos para mí- y “limpiarlo” de todo mal. Ese no es mi objetivo, aunque prometo estudiarlo para indicarles dónde esta el problema de privacidad.

Habilitar el modo de lectura en Iceweasel.

Para activar el modo lectura, está my bien explicado en inglés en este artículo, más sin embargo se los resumo en castellano:

  1. En la BARRA DE DIRECCIONES  escriban “about:config” y presione intro. Recalco lo de la barra de direcciones, que siempre ha existido en los navegadores web y que se ha desvirtuado con páginas de inicio de buscadores y sus cuadros de texto integradas al navegador.
  2. Sale un mensaje de advertencia, cualquier cambio que hagamos puede dar al traste con el funcionamiento del navegador. Prometemos tener cuidado y seguimos adelante.
  3. Se muestran los diversos valores claves con un cuadro de texto que sirven para ubicar rapidamente la variable que buscamos, en este caso “reader.parse-on-load.enabled“, basta ir escribiendo y el navegador va mostrando los posibles valores.
  4. Cuando tengamos ubicada la variable, obervamos que toma un valor lógico verdadero y falso. Basta con hacer doble click para que tome el único otro valor posible, necesitamos que sea VERDADERO.
  5. Una vez cambiado el valor -y sólamente esa variable exacta, no cambiar más nada- procedemos a cerrar el navegador y ejecutarlo de nuevo (no me gusta para nada usar la palabra “reiniciar”: cuando los usuarios comunes escuchan esto reinician el sistema operativo o peor aún, aprietan el botón “reset”, así que cuidado con lo que se traduce del inglés).

Una vez hallamos finalizado el proceso anterior, podemos proceder a probarlo en las páginas web que querramos. Para este entrada funciona el modo de lectura, tanto en Iceweasel 38 en Debian 7 como Firefox 43 en Ubuntu 14 y aunque funciona para las entradas, no para el menú principal, o página principal. Más adelante hablaremos de eso nuevamente.

¿Ya hicisteis tus pruebas, funciona? Sentiros a gusto, probad, probad que vamos a avanzar más en el tema.

Personalizando el archivo “userContent.css”.

En este enlace me percato del código lo que enuncié arriba, lo de aprovechar la amplitud del monitor. También explica cómo modificar el archivo userContent.css e incluso pone que debemos usar la sentencia “!important;” para que Firefox o Iceweasel ejecute nuestras personalizaciones. Pero no funciona, lo probé bien probado y no funciona. Como siempre hay alguien que sabe más que uno, en este artículo confirma lo que había sospechado desde un principio: lo inhabilitaron por seguridad desde la versión 35 por motivo de “Electrolysis” o “e10s”. Es que es muy apetitoso dejar este archivo y su contraparte userChrome.css para inyectarle código malicioso -que se limitará al chascarrillos de formas y colores, letras negras sobre fonde negro, por mencionar algo-. Total que para activarlo se necesita usar la punta de lanza de Firefox: “Nightly” (imagino que cada noche lo actualizan, de allí el nombre). Pero no es necesario que lleguemos a tanto, nosotros -por ahora- no estamos en el equipo de desarrollo, cada quien en su puesto, el de nosotros es probar, probar y probar. Y mejorarlo donde podamos. Es por ello que me parece mejor para nuestros propósitos el usar “Stylish” donde hay cientos de código que podemos usar, mejorar y reusar. Pero, de  nuevo, vayamos paso a paso.

Instalando “Stylish”.

Stylish lo podemos descargar desde la página web segura de complementos para Firefox -fijaros en el candadito verde- donde sale la cara de Jason Barnabe, desarrollador que vive en Winnipeg, Canadá y quien sugiere una contribución (donación) de US$5, el cual los vale. Recuerden que el Software Libre es Libertad, no necesariamente gratuidad, de algo tenemos que vivir los programadores. Si podeís, contribuid con la causa, por favor (ojo que yo no gano nada aquí, es cuestión de sana lógica). Y si no contribuyes monetariamente hablando, pues hala, a escribir código para mejorarlo y compartirlo de nuevo.

The miracle is this the more we share the more we have -Spock - Star Trek
The miracle is this the more we share the more we have -Spock – Star Trek

Este es el milagro: mientras más compartimos, más tenemos. En mi caso pago por alojamiento de este blog ya que no tenemos ISP con direcciones IP fijas en Venezuela donde alojar nuestros propios servidores, en nuestras manos, físicamente hablando. Total que en algo hay que contribuir al Software Libre 8-). Por eso la difusión del conocimiento, de lo que aprendemos, lo difundimos.

Ya instalado el Stylish podemos ya comenzar a personalizar nuestro “modo de lectura”, fin último de esta publicación. Se verá algo parecido a esto:

Stlyish - userstyles.org
Stlyish – userstyles.org

Si desean echarle un ojo al código fuente lo pueden conseguir en Github. Con esta herramiento instalada pasamos entonces a “Herramientas” -> “Complementos” para observar la figura anterior. Luego hacemos click en “Escribir un nuevo estilo” y pasamos a teclear lo siguiente:

@namespace url(http://www.w3.org/1999/xhtml);
@-moz-document url-prefix("about:reader") {
body {
  margin: 0 5%;
  }
}

Nada más que parar recordar la sintaxis de “margin” pueden revisar este enlace donde se explican sencilla y rápidamente los valores que pueden tomar. La instrucción que les comenté “!important;” no es necesaria y la usaremos si y solo si logramos activar el archivo “userContent.css“. Fíjense entonces que lo que hacemos en la primera línea es enunciar bajo qué normas nos regiremos y hacemos referencia al “lector” con las palabras claves “about:reader“. Luego le estableceremos que al contenedor de dicho modo de lectura el margen sea apenas de un 5%. Primero prueben eso, los cambios se realizan al dar click al botón guardar y si tienen alguna página abierta en modo de lectura, ésta tomara los cambios inmediatamente. Me encanta trabajar de esta manera, pues uno puede ver sin dilación el cambio que uno realiza y modificarlo inmediatamente si uno no está conforme. Al principio de este escrito está la imagen de cómo se vería utilizando el color sepia. Ya vamos a hablar del justificado de párrafos, en un momento tocaremos eso. Probad, probad y luego volveís por acá.


Personalizando un poco más.

Ya logramos cambiar los márgenes de arriba y abajo a cero y el izquierdo y derecho a un 5%. Para ajustar justificar los párrafos lo que propongo colocar es lo siguiente:

@namespace url(http://www.w3.org/1999/xhtml);
@-moz-document url-prefix("about:reader") {
body {
  padding: 64px 0;
  margin: 0 5%;
  text-align: justify;
  }
}

Eso sí, la orden es jstificar TODOS los elementos y todos los estilos (a saber 3 en este caso: claro, oscuro y sepia). Si quisieramos aplicarlo sólamente al sepia -mi estilo preferido- eliminamos primero lo anterior (linea 6) e incluimos lo siguiente:

.sepia {
 text-align: justify;
}

Revisando el CSS completo del Reader View.

¿De dónde ha salido ese “.sepia“? Pues para ver TODA la hoja de estilo lo que debemos hacer es, cuando tengamos la págima web en modo de lectura, hacer click derecho y seleccionar “Ver código fuente” (o simplemente presionar {CTRL}+{U}) e ir a la siguiente línea, debería ser la número 8, sino pues bueno, buscad:

<link rel="stylesheet" href="chrome://global/skin/aboutReader.css" type="text/css"/>

Precisamente allí es que declaran la hoja de estilo que vamos a utilizar “aboutReader.css” y el cual debería mostrarse como un enlace web. Lo que explico es válido para cualquier otra página web: le damos click derecho, copiar enlace y abrimos una pestaña nueva y en la barra de direcciones “pegar e ir” e inmediatamente nos mostrará la hermosura del código CSS (gracias a Github por su nueva característica “gist”):

Lo que pueden observar corresponde al código contenido en Iceweasel 38.5.0 y en Firefox 43.0.3 es diferente pero más sencillo

Por supuesto, el Iceweasel “alcanzará” esa versión, pero nunca está demás hacer la respectiva aclaratoria.

Vamos un poco más allá.

Si desempolvamos nuestros conocimientos sobre CSS podemos personalizar aún más, como por ejemplo insertando una imagen de fondo, fija y arriba y a la izquierda y aumentando el margen para que no moleste a párrafo alguno:

@namespace url(http://www.w3.org/1999/xhtml);

@-moz-document url-prefix("about:reader") {

body {
  padding: 64px 0;
  margin: 0 20%;
  background-image: url("http://www.ks7000.net.ve/wp-content/uploads/2015/11/FreeCAD-Ubuntu-150x150.png");
  background-repeat: no-repeat;
  background-position: left top;
  background-attachment: fixed;
  }
.sepia {
  text-align: justify;
  }
}

¿Y qué tal si cambiamos el color de fondo que NO nos gusta en determinada página web? Aquí es donde realmente vamos un poco más allá del tema original, sólo lo coloco para que vean qué tanto se pueder hacer con “Stylish“: pongamos como ejemplo la dirección web “www.soporteweb.com”, la cual  nos devueve la dirección IP de nuestro modem (proporcionado por nuestro ISP) -y la cual no debemos confudir con nuestra dirección IP de Red de Área Local LAN-.

Pues bien, lo que debemos hacer es ir de nuevo al menú “Herramientas->Complementos” (CTRL+SHIFT+A) y seleccionamos “Stilysh” -estilos de usuario- y hacemos click en “Escribir un nuevo estilo” y procedemos a teclear lo siguiente:

@namespace url(http://www.w3.org/1999/xhtml);

@-moz-document url("http://www.soporteweb.com/") {
  body {
    background-color: lightgrey;
  }
}

Le damos “guardar” y ya podemos ir a la página deseada a comprobar si nos aplica el color de fondo deseado, un gris claro.

Develando el funcionamiento del Reader View.

Pues ya ven que pueden seguir haciendo sus estilos, ya sea al Reader View o “directamente” a la(s) página(s) web deseada(s). Vale aclarar que el “Stylish” permite verificar la sintaxis e incluso sugiere elementos con menues contextuales -o tooltips, como queraís decirle-. Y lo más importante, si se nos complica algo, ¡pues borrón y cuenta nueva!: no tenemos nada que restaurar, ya que cada página tomará el estilo que sus creadores se esforzaron en colocarle, ni más ni menos.

Mozilla Firefox 50.

Actualizado el martes 15 de noviembre de 2016.

Hoy damos cuenta de la actualización del navegador web Mozilla Firefox 50, el cual trajo unas serie de novedades pero en cuanto al modo de lectura para páginas web AHORA podemos simplemente presionar las teclas CONTROL+ALTERNO+R (si la página visitada se comporta como escribimos anteriormente y puede ser activada en modo lectura). Para más información sobre las demás novedades haced click sobre el enlace de nuestro mensaje en Twitter (osea “tuit”) siguiente:

 

GNU Linux Turnkey 14.

GNU Linux Turnkey 14.

GNU Linux Turnkey LAPP 14 es una distribución pensada para instalar-y-usar con un buen conjunto de aplicaciones (LAPP abreviatura de Linux, Apache, Postgresql y PHP) sin descuidar la seguridad (instala claves SSH inmediatamente –algo que deberíamos hacer nosotros mismos-) y un conjunto de valores predefinidos que agilizan nuestro trabajo al montar servidores para la producción, todo esto con las características intrínsecas del Software Libre. CUENTA ADEMÁS (servicio que hay que pagar, eso sí) con DNS y respaldos “en la nube” ya que de algo tienen -tenemos- que vivir los programadores.


Yo sigo la cuenta Twitter del sr. S. Vaughan-Nichols quien siempre tiene interesantes reportajes (y abundantes críticas) sobre el mundo de la informática, muy especialmente en los temas de servidores y lo que está de moda ahora: “la nuuuuuuube” (imaginen tamborileo en paralelo). Él siempre alega la SIMPLICIDAD (muchos lo llamamos “K.I.S.S. principle“) y no sólo critica por criticar sino que ÉL TAMBIÉN APORTA SOLUCIONES.

Es por tanto que me llamó poderosamente la atención el siguiente “trino (tweet)”:

Sigo el enlace, leo el artículo, sigo el otro enlace hacia los creadores de la distribución TURNKEY, noto que en cada artículo colocan el enlace para descargar la imagen ISO con la “distro” más la aplicación deseada -amd64, por supuesto, estamos hablando de servidores-, todo muy bien explicado y detallado (en idioma inglés) y en 5 minutos la descargo y en 2 minutos más la ejecuto en un ambiente VirtualBox y listo, tengo corriendo un servidor LAPP en modo live CD y casi listo para producción. ¿NO ME CREEN? Veánlo “con sus propios ojos”:

La genial idea de los programadores de Turnkey estriba en adaptar una distribución Linux para que, siguiendo los preceptos de la licencia GNU, sea libre y sin embargo si uno desea seguir adelante con un servidor DNS y respaldo de datos en los servidores Turnkey de manera paga y con una genial API KEY en poco tiempo estemos en línea y produciendo dinero.

Esas cosas las admiro profudamente: simplicidad, apoyo inicial y si quieres CRECER allí están para convertirse en socios de manera instantánea. Además  observo que Turnkey no trabaja sola, también vende servicios Amazon para alojamiento, si es que uno no tiene máquina propia para montar lo requerido.


Instalación de Turnkey.

En otras publicaciones he descrito cómo instalar un servidor PostgreSQL y cómo administrarlo con phpPgAdmin paso a paso. Siempre es bueno saber hacerlo todo uno mismo y luego que uno ya haya aprendido no está mal que obtener ayuda extra como la concebida en esta maravillosa distribución Linux Turnkey. A pesar que en los enlaces anteriores describo en detalle el entorno que utilizo, describo un resumen: uso VirtualBox en Ubuntu 64 bits, le asigné 512 megabytes en RAM, 1 CPU, 12 megabytes para vídeo y la única tarjeta de red virtual la configuro como “puente” para que la máquina virtual Turnkey se comunique con mi enrutador inalambrico (y de allí a la internet) quien se encarga del trabajo DHCP y le asigna la dirección 192.168.1.131 con los Norton DNS.

La instalación en sí la vieron arriba en el video que subí -alojamiento cortesía de Youtube- y el detalle adicional es que RECUERDEN BIEN que la distribución del teclado es en inglés [yo hace años que dejé de usarlos, ni siquiera en español tengo ya, sólo distribución Latinoamericano, ojito al meter las contraseñas 😉 ]


Primera vista a Turnkey.

Para el sr. S. Vaughan-Nichols, quien lleva años trabajando con PhpMyAdmin, probó el Adminer y le resultó agradable; en mi caso veo una sencilla interfaz que va directo al grano y sin complicación alguna: yo la recomendaría para aprendizaje previo al PhpMyAdmin y/o PhpPgAdmin.

La primera diferencia que hallo es que para poderme conectar por el explorador de internet (en mi caso Mozilla) debo utilizar el prefijo https. Como les comenté, la seguridad no ha sido descuidadada en esta distribución, ya que genera sus propias claves al instalar la distro Turnkey (en nuestro caso “correr” live CD). Si quieren conocer al detalle los de las claves SSH y su administración recomiendo leer el siguiente post del Maestro Twitter @Phenobarbital Sr. Jesús Lara.

Como dichas claves SSH no están avaladas por un tercero de confianza el navegador hace la debida advertencia de seguridad a la cual le estableceremos unas indicaciones para nuestras pruebas en el servidor virtual Turnkey (si adquirimos una llave API tipo TKLBAM con Turnkey NADA de lo siguiente que explico haría falta hacer).

Turnkey 01
Conectando por primera vez para administrar Turnkey en una máquina VirtualBox.

Como ven el en gráfico anterior haremos click en “comprendo los riesgos” y luego “agregar excepción”. Esto sólo lo haremos con nuestras máquinas que corren en nuestra propia red de área local, jamás ni nunca lo haremos con otros sitios web en internet (sigamos los consejos de seguridad de SUSCERTE).

Turnkey 02
NO agregaremos como permanente la excepción de seguridad.

NO agregaremos como permanente la excepción de seguridad ya que sólo hacemos esto con propósitos didácticos, recuerden que corremos el servidor en RAM -live CD- y cada vez que lo reiniciemos imagino genera nuevas claves SSH así que no embasuremos nuestro querido navegador web ADEMÁS que si hacemos pruebas con otras máquinas virtuales y el enrutador les asigna la misma dirección IP local nos saldrán otros mensajes de advertencia de seguridad, OSEA no nos embaserumos nosotros mismos a la hora de aprender a programar.

Turnkey 03
Portada principal para administrar Turnkey.

Lo primero que vamos a ver es el Adminer LAS FLECHAS ROJAS en las imágenes son de mi autoría para guiarnos paso a paso, hacemos click a donde ellas apuntan.

Turnkey 04
Usando Adminer,
login “posgres”.

El usuario -o “login”- es la palabra “posgres” y la contraseña la que hallamos colocado al instalar -o correr- el Turnkey.

Turnkey 05
Administrando PostgreSQL con Adminer.

En fin, hagan uso de su albedrío y creen bases de datos, agreguen tablas y/o índices, clonen, jueguen y aprendan. Recuerden que como estamos ejecutando un live CD al reiniciar la máquina se perderán todos los datos. Mi imaginación vuela en este caso: si adquirimos una API key que nos permita respaldar con los servidores de Turnkey y una vez hecho eso, apagamos y pudieramos levantar otro servidor virtual en cualquier otro sitio restaurando los datos desde Turnkey, aunque imagino que eso tendrá su costo adicional, respaldar y restaurar con frecuencia. No soy el único en Venezuela que conoce TurNkey ya hay varios usuarios “corriéndolo” en Venezuela: Maracaibo, Barquisimeto, Araure [ ¿? ], Valencia, Puerto Cabello, Maracay, Cumaná y, ¡cómo no!, Caracas.

Turnkey 10
Servidores (al día de hoy 27sep2015) corriendo Turnkey en Venezuela.

Mi imaginación va mucho más allá: la manera como programaron a Turnkey se puede prestar para montar servidores maliciosos. El pequeño detalle es que deben pagarle a Turnkey con una tarjeta de crédito cuyo dueño es localizable por los bancos de manera rápida y si usan una tarjeta robada o extraviada igual es delito federal en los EE.UU. así que esa opción, como ven, queda descartada.


Administrando a Turnkey.

Turnkey 00
Pantalla de bienvenida a Turnkey.

En esta pantalla de bievenida que veremos por cónsola nos muestra un resúmen sobre cómo conectarnos vía remota y ya analizamos como entrar en el apartado anterior. Hago hincapié en la publicidad: si adquirimos una API key TKLBAM la debemos introducir en el cuadro de diálogo anterior y esperar que se realicen las actualizacions y/o instalaciones para montar BIEN EN SERIO UN SERVIDOR PARA PRODUCIR DINERO. Ese tema, por ahora ni lo tocaremos ni lo revisaremos.

Turnkey corriendo en VirtualBox.
Turnkey corriendo en VirtualBox.

Lo que si que vamos a hacer es echar un ojo a las opciones para administrar nuestro futuro servidor:

Turnkey 03
Portada principal para administrar Turnkey.

¿Recuerdan la portada principal? PUES ESTA VEZ HACEMOS CLICK EN EL ÍCONO QUE DICE WEBMIN, olvídense por un momento de la flecha roja [qué pichirre soy con el alojamiento web, NO voy a subir otra imagen nada más que para apuntar con otra flecha roja ja ja ja 😉 ]

Turnkey 06
Entrando a Webmin como usuario “root”.

Usaremos las credenciales de usuario raíz -“root”- y si éste fuera un servidor para producción lo primero que haríamos es crear los usuarios correspondientes y no volver a tocar la dichosa cuenta. Acá como estamos aprendiendo y jugando pues no haremos nada de eso. La contraseña pues, halá, la que introdujimos al instalar -o correr-:

Turnkey 07
Menú principal Webmin.

Sinceramente quedé abrumado por la cantidad de opciones del Webmin lo único que se me ocurre para describirles la aplicación es que es como si estuvieramos sentados en la cónsola del servidor, pero con una interfaz gráfica de la cual carece -excepto de esta manera remota-. Podemos agregar los usuarios que les dije, reiniciar o apagar el equipo (partimos de que estamos conectados por https o SSH y bien seguros), instalar o quitar aplicaciones, configurar la red (ojito con desconectarnos nosotros mismos) y cualquier otra cantidad de cosas. Incluso para nuestro aprendizaje (nunca para un servidor en producción) podemos instalar “Google Gears” -un proyecto que aunque abandonado desde marzo de 2011 seguirá existiendo por SVN – e incluso lo podemos exportar y mantenerlo en nuestro propio espacio GitHub (nada malo ha pasado con el alojamiento de proyectos de código abierto ofrecidos por este gigante, sólamente reconocen que GitHub es mucho mejor e incluso ellos se mudaron también; YO DIGO QUE ES OTRA VICTORIA PARA LINUS TORVALDS Y RICHARD STALLMAN, un proyecto abandonado de software libre puede ser mantenido perfectamente por otros que aún lo consideren importante):

Turnkey + Webmin + Google Gears
Turnkey + Webmin + Google Gears.

Como son muchas las opciones que tiene el Webmin sólamente les mostraré las capturas de pantallas de las opciones del menú:

Webmin opción principal
Webmin opción principal
Webmin opción "system".
Webmin opción “system”.
Webmin opción "servers".
Webmin opción “servers”.
Webmin opción "tools".
Webmin opción “tools”.

 

Webmin opción "networking".
Webmin opción “networking”.
Webmin opción "hardware".
Webmin opción “hardware”.

Apagado de Turnkey virtual.

Espero hayan disfrutado de este post tanto como yo, hoy aprendimos algo nuevo y sólo queda apagar la máquina virtual por (faltaba más faltaba menos) por medio de Webmin:

Apagado de servidores remotos por Webmin.
Apagado de servidores remotos por Webmin.

 

<Eso es todo, ¡por ahora!>.

Cambiar refresco de pantalla en Debian.

Con el paso de los años mi visión se ha debilitado. Por eso decidí desempolvar mi viejo monitor Samsung LCD 740n que tiene una estupenda tasa de refrescamiento vertical de 75 Hertz, es decir, “dibuja” el monitor 75 veces por segundo lo cual hace más placentero ver un monitor durante horas y horas todos los días. Yo sabía que por defecto viene fijado en 60 Hertz aunque no sabía el por qué, investigando un poco encontré este artículo donde dan una explicación histórica, dos grandes verdades que en mi mente no las había unificado hasta ahora. Las razones del por qué cansa menos la vista mientras mayor sea la tasa de refrescamiento por segundo siempre lo he tenido presente pero en este otro artículo está pero que muy bien explicado.

Finalizado el preámbulo vamos al grano, cambiar el refresco de pantalla (y resolución) en Debian (e incluso otras distribuciones Linux pero aún no lo he probado ya que las máquinas virtuales con las que practico pues… ¡usan el mismo monitor todas!). Esto quiere decir que este tema es con HARDWARE REAL pero primero he de hacerles una advertencia, no vayan a decir que no se los advertí:

Establecer una tasa de refrescamiento a un monitor para la que NO ESTÁ DISEÑADO, PUEDE DAÑAR SU MONITOR.

De hecho lo dañará si aún tiene un monitor de rayos catódicos (CRT, del inglés Cathode Ray Tube), en el caso de los monitores LCD y LED pues simplemente se niegan a trabajar y como no confirmamos al sistema operativo el ajuste, pasado cierto tiempo lo devolverá a su estado anterior. Si dudan de mi palabra lean la advertencia de Microsoft y otros foros importantes sobre tarjetas de video.

Actualmente esto no es problema para los monitores “en tercera dimensión 3D” ya que refrescan mínimo a 120 Hertz (60 para cada ojo) y así se produce la ilusión de profundidad, con dos imágenes tomadas desde dos puntos separados por cierta distancia, tal como vería nuestros ojos humanos (suena sencillo ¿verdad?).

Gaceta Oficial Extraordinaria N° 6.181: aumento sueldo 20+10% 1° mayo 2015.

Son 2 hojitas en formato pdf  (agradezco a “pdfsam” y lo recomiendo para dividir y combinar documentos en ese formato); con este aumento el sueldo mínimo en Venezuela se ubica en Bs. 7.421,68 (si tomamos como referencia el SIMADI serían aproximadamente US$ 37 mensuales).

Para descargar dicho ejemplar electrónico de la Gaceta Oficial desde nuestra página web haga click aquí.

Si desea descargarla desde el Tribunal Supremo de Justicia.

<Eso es todo, por ahora>.

Curso básico de HTML 5.

Ya usted, ellos, ellas y yo lo sé: hay infinidad de tutoriales en internet sobre HTML: sería “llover sobre mojado” volver a tratar el tema, pero ¿quién dijo miedo? 😉

En mi caso, el que me ocupa, es actualizarme al HTML 5 y enfrentar a dos viejos “demonios” en esto de la creación de páginas web. Y no, no me refiero a los servicios en GNU/Linux a los cuales llamamos “D.A.E.MON” si no a los dos grandes problemas que debemos enfrentar antes de comenzar a escribir una sola línea de código en HTML:

  1. La multitud de navegadores web existentes y el legado que traemos a rastras, ya que muchas personas se niegan a actualizar sus programas. Agreguemos a eso las particularidades de los nuevos celulares con Android y ni mencionemos los celulares con WAP (y por ende WML) que aún están en uso con sus micronavegadores.
  2. Los gustos de nosotros los seres humanos en cuanto a diseño, colores y funcionalidad de las páginas web (en otra entrada presentaré las hojas de estilo en cascada con las cuales enfrentaremos este aspecto).

Y para no abrumarlos ni abrumarlas más comienzo de una vez el tema.

Prefacio.

La “World Wide Web”, tal como la conocemos hoy día, vino de la genial idea del profesor Tim Berners-Lee (inspirado por Ted Nelson y convencido por Richard Matthew Stallman) y es quien actualmente aún lleva las riendas al presidir la “World Wide Web Consortium“, una organización creada en 1994, que agrupa a nivel mundial a más de 300 entes y quienes en conjunto recomiendan las normas del HTML. Y sí, leyeron bien, RECOMIENDAN las normativas ya que el HTML no es en realidad un lenguaje de programación sino un lenguaje de marcado, que además descansa sobre dos tecnologías llamada URL y HTTP. Por ahora sólo necesitamos saber de dónde viene y cuál es la situación actual, si quereís ahondar en conocimientos allí mismo teneís los enlaces (gracias de nuevo Señor Tim Berners-Lee).

Los lenguajes de marcado son (y para poder explicarlo y que sea comprensible rápidamente) como el antiguo dictado oral que hacíamos a las secretarias y/o mecanógrafas (casi siempre eran mujeres por su talento natural para lidiar con formas, colores y seres humanos) en el siglo pasado:

“Ponga estilo de carta. ponga comillas, ponga mayúsculas, Estimado Juan, ponga dos puntos, aparte, sangría, ponga primera letra mayúscula, te escribo esta carta, ponga negrillas, de forma muy urgente, cierre negrilla, ya que no me has enviado… etcétera“.

Y para los que nacimos y tuvimos la oportunidad de vivir en el siglo pasado, cada empleada tenía su manera de escribir y presentar las cartas, de allí la actuación de los navegadores web, cada uno ofrece ventajas y desventajas y cada quien escoge de acuerdo a sus necesidades.

Aclaratoria.

A menos que se diga expresamente lo contrario, todo a lo que nos refiramos es HTML versión 5, la del año 2014, la recomendada. Por supuesto que las etiquetas html presentan cierta compatibilidad hacia atrás, y también hay unas totalmente nuevas para esta versión. No entraré demasiado en dichas compatibilidades, si quereís estudiar ese aspecto por favor seguid los enlaces que presento a lo largo y ancho de la entrada. Si ya sabéis, habéis adquirido conocimiento con antelación, os recomiendo un tema más avanzado escrito en este mismo blog: Un CAPTCHA fácil y sencillo de implementar“.

Otra cosa que os parecerá harto extraño (pasado el tiempo lo comprenderíes con la experiencia que logréis) yo seguiré la siguiente consigna:

“Cualquiera puede equivocarse, excepto nosotros“.

¿Qué significa lo anterior? Que seremos más estrictos en la sintaxis del HTML pero sin llegar a declararnos explícitamente como XHTML, así tendremos lo mejor de ambos mundos.

Mi primera página web.

Así que llegamos a dar nuestros pininos en el internet como protagonistas y no como simples lectores. Las páginas web descansan en archivos de texto plano con la extensión .htm o para los sistemas operativos modernos .html y dichas extensiones permiten que identifiquemos qué tipo de contenido albergan más sin embargo para nuestras computadoras el contenido es lo importante. Es así que debemos conocer nuestro primer elemento del lenguaje HTML dentro del archivo nombrado (recordemos que los nombres de archivos son sensibles a mayúsculas y minúsculas):

<!doctype html>

 Como vemos comienza con el signo “mayor que” y finaliza con “menor que”. He aquí la primera diferencia con los lenguajes de programación: aquí dichos símbolos carecen de significado matemático alguno, sirven más bien como delimitadores. Ya que le damos ese uso, nuestra mente cambia el enfoque y los asocia a los paréntesisque trabajan por pares donde uno “abre” y el otro “cierra”. Dentro de esta categoría están los corchetes y luego las llaves: ( [ { } ] ) , en ese orden anidado. Como son rectos y se parecen más a los corchetes que a los otros dos optamos por llamarlos corchetes angulares y así son llamados en inglés angle brackets (y en inglés antiguo chevrons). Y hemos de referirnos al inglés porque precisamente es éste el idioma en el que está escrito el HTML, angle brackets es la traducción literal de corchetes angulares.

Dentro de estos delimitadores está el cierre del signo de admiración acompañado de la palabra doctype que es un recurso nemotécnico abreviado de  “DOCument TYPE” y traduciremos como “tipo de documento” acompañado, por supuesto, de la palabra html. Para este caso particular el uso de mayúsculas y minúsculas es indistinto pero tiene una excepción: como esta declaración se incluye por compatibilidad con anteriores versiones del lenguaje y dichos identificadores para cada versión son un tanto largas y complicadas y de paso eran obligatorias se decidió incorporar lo que yo llamo “un relleno” que debe ser escrito literalmente y entre comillas dobles o simples para aquellos servidores que buscan estos identificadores: dicha sentencia es “about:legacy-compat” que viene a ser leida por nosotros como “acerca de:compatibilidad heredada”. Nuestra primera linea quedaría de la siguiente manera:

<!doctype html system "about:legacy-compat">

La segunda linea a continuación define la página web en sí y tiene el propio nombre html para declarar dónde comienza y dónde termina:

<html lang="es-419"> ... </html>

Donde están los puntos suspensivos colocaremos todo el código, notemos la nomenclatura para definir el idioma y región de nuestro país según el organismo Naciones Unidas: “es-419”; (y ratificado por el W3C en esta página, sin embargo muchos utilizan la norma ISO 639-1 ambos son válidos si recordamos que la W3C sólo recomienda, no obliga) y si necesitaramos programar para alguna otra región del mundo acá está el resto de los códigos.

A partir de este momento colocaré el código completo de la página web las cual ustedes introducirán con el editor de texto de su preferencia, hay muchos, a mi me gusta el nano, notepad++ y gedit. Para uso avanzado están vi y vim. Las capturas de pantalla que verán son tomadas al gedit que viene con ubuntu al cual le hice unas cuantas modificaciones de perfil, para verlas en detalle haga click aquí.

<!doctype html system "about:legacy-compat">
<html lang="es-419">

</html>

Nosotros los seres humanos necesitamos, nos gusta, tener información adicional que nos guía o aclara el código pero que para las máquinas no tiene relevancia. La manera de que ellas “ignoren” dichos datos es colocándolo como comentarios con la siguiente sintaxis:

<!-- ... -->

Donde están los tres puntos insertamos el comentario que deseemos, no importa si ocupa varias lineas pero lo importante es que tengan su apertura y cierre. ¿Recuerdan que les dije que gedit lo utilizo con una configuración especial? Comparen el código que llevamos en purito texto plano y vean como lo presenta el editor de texto gedit:

<!doctype html system "about:legacy-compat"><!--Declara HTML5-->
<html lang="es-419"><!--Escrito en castellano de América-->

</html>

-primera_clase.html (~) - gedit_029

¡Qué diferencia! Al suministrar el nombre al archivo, con todo y extensión, gedit automáticamente codifica al lenguaje html como pueden obervar en la barra de estado inferior de la ventana.

El siguiente paso que haremos es ir a la carpeta donde guardamos nuestro archivo ( al que le dimos el nombre “primera_clase.html”) y lo abrimos ya sea con doble click, click izquierdo o click derecho+abrir en navegador. Cada sistema operativo moderno tiene un navegador web predeterminado, así es que se puede visualizar nuestra primera página web, MÁS SIN EMBARGO NO VEREMOS NADA PUES AÚN FALTAN MÁS LÍNEAS DE CÓDIGO. ¿Por qué entonces yo pido abrirla de una vez, sin más?

La respuesta es: pedirle al navegador web que nos muestre la página web que estamos haciendo para visualizar el código fuente (generalmente haciendo click derecho sobre nuestra página web abierta en navegador). Quiero hacer énfasis que una página web, a pesar de todo nuestro empeño de escribirla bien -según las recomendaciones- depende de algunas cosas más. Les muestro lo que interpreta nuestro navegador web, en este caso Mozilla Firefox:

Fuente de: file:---home-jimmy-primera_clase.html - Mozilla Firefox_015

El punto que quiero recalcar es la palabra América la cual se muestra incorrectamente, con unos caracteres extraños, así que hemos de reparar en que nuestro bello idioma castellano sea escrito (y visualizado) correctamente. A pesar de derivar del latín, (idioma que nunca tuvo acentos ni signos ortogŕaficos) con la evolución de nuestro idioma se llegó a un lenguaje de marcado (ver inicio de esta entrada) que ayuda muchísimo a transmitir mejor las ideas; o lo que yo llamo “degustar las palabras”. Es por ello que en el lenguaje HTML se tomó la previsión de mostrar correctamente dichos caracteres con etiquetas especiales, así tenemos que para mostrar nuestras vocales acentuadas y la letra eñe (las mayúsculas siguen la misma normativa):

á -> &aacute;
é -> &eacute;
í -> &iacute;
ó -> &oacute;
ú -> &uacute;
ñ -> &ntilde;

Y para los acentos en idioma catalán y francés (aquí podeís ver una lista de los más utilizados):

à -> &agrave;
è -> &egrave;
ì -> &igrave;
ò -> &ograve;
ù -> &ugrave;
â -> &acirc;
ê -> &ecirc;
î -> &icirc;
ô -> &ocirc;
û -> &ucirc;

Si insertamos los anteriores caracteres “especiales” (no usados en el idioma inglés) en nuestra primera página web, la guardamos y abrimos con nuestro navegador web (y pedimos visualizar nuestro código fuente) veríamos algo similar a esto en el programa gedit:

primera_clase.html (~) - gedit_019

Y en el navegador web Mozilla Firefox:

Área de trabajo 1_016

Como pueden notar el navegador cumple con su trabajo de mostrar los caracteres especiales, más sin embargo podemos observar que la palabra América en el comentario sigue sin visualizarse correctamente y no, no es porque no utilicé el &ecute; (si quieren hagan la prueba) es por otro motivo más importante. Y, yo ya se que los comentarios no revisten importancia, pensarán ustedes, total eso no se muestra en nuestra página web, sigamos adelante y comprenderán.

Mi primera página web es en castellano.

Ya que hay muchísimas páginas web en inglés, pues vaya que le toca al castellano llenar espacio. Antes de proseguir debo aclarar que lo que los voy a comentar lo aprendí en esta página web. (si no está en línea, prueben este otro enlace). Si quieren saber la historia de la codificación de caracteres puede leer (en inglés) esta otra página web del lenguaje de programación Python. Debemos indicar también que tocaremos brevemente ciertos aspectos inherentes a los programas que sirven páginas web, “servidores web”.

Volviendo a nuestro archivo de texto plano con extensión .html y editado con el programa gedit debemos tener especial cuidado en guardar dicho archivo en la codificación de caracteres utf-8 tal como muestro al escoger la opción “Guardar como”, les resalto con una elipse para acentuar la opción:

Guardar como_035

¿Por qué usar UTF-8 en vez de otros sistemas de codificación?

La respuesta les va a sorprender (y el que me quiera refutar, por favor escriba abajo en los comentarios): USAMOS EL UTF-8 POR COSTUMBRE HEREDADA DEL IMPERIO ROMANO, nacido además en Grecia, cuna de nuestra civilización occidental. Es así, de hecho, que en marzo de 2015 el 83% de las páginas web utilizan esta codificación, y de paso es la recomendada por la World Wide Web Consortium (W3C) por su compatibilidad hacia atrás con la codificación ASCII y hacia adelante con los caracteres (o más bien ideogramas) orientales (hindi, coreano, chino, etc). Esta “compatibilidad hacia adelante” se ve sacrificada por el aumento de bytes en página ya que el UTF-8 fue pensado para ser de longitud variable: si escribimos en cualquier lengua indoeuropea usaremos menos espacio y si escribimos en ideogramas usaremos un poco más de espacio. Es por ello que elegimos UTF-8 PERO NO SE LIMITEN A ELLO si se les presenta la oportunidad de trabajar en otro país de Asia (ejemplo loable cuenta Twitter: @Kopepasah ), si ese fuera su caso, están las codificaciones UTF-16 y la más completa por ahora UTF-32 (vean aquí cómo se estructuran los caracteres); agregarlas a nuestro programa gedit es bien fácil, sólo hacemos click en la ‘flechita’ de codificación de caracteres (ver gráfico anterior) y escogemos “añadir o quitar” y nos muestra este cuadro de diálogo:

Códigos de caracteres_037

Seleccionamos la codificación que necesitaramos y listo, lo guardamos en esa codificación PERO CON EL CUIDADO ESPECIAL DE ESPECIFICARLO EN NUESTRA PÁGINA WEB.

El metacomando para declarar la codificación de caracteres escogida es:

 y debe ser incluida en el meta comando head:

<head><meta charset="UTF-8"></head>

Sólo queda informar dos detalles más acerca de esto y es referida explícitamente al programa servidor web Apache utilizado ampliamente en el mundo:

  • Lo correcto es que incluyamos dicha sentencia en todas y cada una de nuestras páginas html pero hay quienes piensan que debemos simplificarnos la vida y configurar a Apache a que automáticamente ‘emita’ nuestra página web con dicha configuración UTF-8.
  • Debido a lo anterior podemos especificar en el archivo .htacces en el directorio raíz de nuestro sitio web (subdirectorios ‘heredarán’ la configuración) que contenga la sentencia “AddDefaultCharset UTF-8“.
  • Si se configura según el punto anterior, el servidor obviará la sentencia que coloquemos en el fichero .html: si por ejemplo especificamos <head><meta charset=”UTF-16″></head> se obviará UTF-16 y será emitido como UTF-8.
  • Si especificamos en el fichero /etc/apache2/conf.d/charset la sentencia “AddDefaultCharset UTF-8” tendrá el mismo efecto con la diferencia que afectará a todos y cada uno de los sitios web alojados en ese servidor (esta configuración es muy común para ahorrar hardware con sitios web de poco tráfico).
  • Es por tanto que recomendamos agregar en el archivo .htacces la sentencia “AddDefaultCharset OFF” y simplemente a cada archivo .html le especificamos <head><meta charset=”UTF-8″></head>.
  • De ser posible que tengamos acceso /etc/apache2/conf.d/charset (osea, el servidor está entera y únicamente a nuestro sitio web) agregarlo allí también para mayor seguridad (si desea saber más vaya usted a este enlace).
  • Para finalizar este punto, existe un método para indicar la codificación de caracteres empleando lenguaje PHP pero escapa al alcance de este tutorial, no obstante anótenlo para tenerlo siempre presente cuando evolucionemos.

Agregando más comandos a <head></head>.

Al comando para declarar la codificación de caracteres, agregaremos las siguientes etiquetas para que el navegador muestre nuestro título de página en la ventana , si es que el dispositivo lo permite (por ejemplo los celulares no lo hacen):

<title>Titulo de la página web.</title>

En dicha cabecera (que sería la traducción al castellano), además de <meta> y <title> admite los siguientes elementos:

  • <style>…</style>:permite especificar estilos como color de fondo, color de texto, etc. aplicadas a cada sección o texto de la página web.
  • <link>: si por el contrario queremos especificar dichos estilos en un archivo aparte para servir distintos archivos .html en un mismo directorio, podemos usarlo y ahorrar esfuerzo y espacio en disco. No tiene etiqueta de cierre. Dichos aspectos son cubiertos por las Hojas de Estilo en Cascada (cascading style sheets o CSS) y las presentaremos en el siguiente capítulo, por ahora basta saber que la sintaxis será (ejemplo): <link rel=”stylesheet” href=”mystyle.css”>
  • <script></script>: sirve para encerrar código en lenguaje de programación interpretado del lado del cliente (nuestro navegador web) denominado JavaScript (aunque también tiene una versión del lado del servidor). Merece una entrada totalmente aparte.
  • <base>: permite especificar una directorio diferente al que por defecto está nuestra página web. No tiene etiqueta de cierre. En nuestro caso, por ejemplo, nos serviría para especificar imágenes alojadas incluso en otro servidor web (si lo permite) ahorrándonos la escritura de código adicional. Ejemplo: <base href=“http://www.w3schools.com/images/”>
  • Por último volvemos a la etiqueta <meta></meta>, la cual puede contener numerosos valores, ya vimos charset pero además acepta name, http-equiv, e itemprop.

Como pueden ver, las opciones se nos agigantaron rápidamente, pero cuando algo es complejo debemos picarlo en trozos para luego digerirlos uno por uno. Volviendo a nuestra primera página quedaría de la siguiente manera:

Mi primera página web es en castellano

página web y código fuente

Cuerpo de página:la etiqueta <body></body>.

Como pueden observar hasta ahora lo único  “visible” que hemos hecho son los caracteres especiales los cuales incluimos con propósitos didácticos. Para estar en lo correcto debemos encerrarlas entre las etiquetas <body>…</body>, donde están los puntos supensivos. Dentro de estas etiquetas irá toda nuestra página web ordenadas con las siguientes etiquetas:

  • <header></header>: un resúmen de la página, pudiéndose indicar además algún ícono y/o datos del autor. Se pueden declarar varias veces, de ser necesario, aunque nuestro estilo será declararlo una sola vez por página.
  • <section></section>: donde se desglosará lo planteado en el punto anterior pero además debemos encerrarlos entre <article>…</article>. Se pueden declarar las veces que sean necesarias, pero recuerden anidar correctamente cada uno: <section><article></article></section>.
  • Refinando el punto anterior, HTML5 no manda ni ordena anidar de la forma en que yo lo explico pero ¿A quién NO le gusta el orden y sentido?
  • Si queremos mostrar una figura e incluso colocarle un texto descriptivo usaremos <figure> </figure> y <figure> (imagen) <figcaption> (texto) </figcaption></figure>.
  • Si queremos mostrar un menú lateral debemos usar <aside></aside>.
  • Para finalizar el elemento de pie de página <footer></footer> donde podemos indicar autoría, licencias de uso, datos de contacto, mapa del sitio o enlaces externos o internos como siguiente o previo.
  • NÓTESE EL EXTRAORDINARIO PARECIDO con escribir un libro:
    1. Datos de imprenta: <doctype>.
    2. Lomo del libro: <head> y <title>.
    3. El libro en si mismo: <html>.
    4. Prólogo y/o índice: <header>.
    5. Capítulos y subcapítulos: <section><article>.
    6. Imágenes y/o gráficos explicativos: <figure>.
    7. Comentarios al margen: <aside>.
    8. Pie de página -mayor analogía imposible-: <footer>.

Diseño de página.

Llámenme “conservador” pero Gutenberg y el medioevo siguen vigentes hoy día, así como físicamente un libro debe ser diagramado según unos valores armónicos, nosotros también debemos otorgárselo a nuestra página web. He aquí cómo se hacía antes y hacia adonde vamos ahora:

Popularized by Jan Tschichold in his book The Form of the Book in 1975.
The Van de Graaf canon is used in book design to divide a page in pleasing proportions. This canon is also known as the “secret canon” used in many medieval manuscripts and incunabula. The page proportions vary, but most commonly used is the 2:3 proportion. In this canon the text area and page size are of same proportions, and the height of the text area equals the page width.

Tal como en la antigüedad se dieron a la tarea de diagramar los libros hoy en día hay gente que se ha dado a la tarea de ahorrarnos ese trabajo con unos marcos de trabajo (framework) para el lenguaje HTML pero eso lo explicaré en su entrada respectiva.

En este punto les muestro cómo es la estructura de cualquiera página web, lo que está en color blanco es lo que nos muestra finalmente nuestro navegador web preferido:

HTML page structureEn el gráfico anterior, si detallan bien, hay dos elementos que aún no he explicado: son los comandos que nos permiten insertar un título y su párrafo correspondiente; ¿recuerdan la analogía con un libro? Pues ahora vamos a ello.

Títulos y párrafos.

Los títulos que deseemos deben ir dentro de la siguiente estructura de comando, siendo 1 el tamaño más grande y el 6 el más pequeño. No debemos preocuparnos por la fuente de letra que utilice el navegador, dicho programa al leer  el tamaño del título se encargará de mostrarlo adecuadamente.

<h1>Título 1.</h1>
<h2>Título 2.</h2>
<h3>Título 3.</h3>
<h4>Título 4.</h4>
<h5>Título 5.</h5>
<h6>Título 6.</h6>

Acá pueden observar, “en vivo”, cómo se mostraría nuestra página web en castellano en su navegador favorito o escogido para leer mi enseñanza.

primera_clase_titulos_y_parrafosAntes de continuar debo explicaros ciertos detallitos con propósitos didácticos y prácticos:

  • Ya nuestra página tiene 35 líneas y es difícil de mostrar en una sola captura de pantalla, si haceís click en la última imagen podrán verla en una ventana (o pestaña) nueva en su tamaño original.
  • El código indentado facilita la legibilidad a los humanos pero ocupa espacio -tanto en disco como en tráfico- cuando el usuario solicita la página.
  • Dicho código indentado me fue posible escribirlo rápidamente con la personalización que le hice a gedit, el indentado ayuda a visualizar y los resaltados de colores nos ayuda a encontrar errores de sintaxis.
  • Podríamos eliminar los “espacios sobrantes” a fin  de optimizarla para cuando la vayamos a publicar pero dicho trabajo es titánico a la larga.
  • Además podríamos indicarle a nuestro servidor Apache que comprima todo lo que vaya a enviar a los usuarios, pero ese tema escapa a este tutorial.
  • Debido a todo lo anterior en lo sucesivo sólo explicaré el comando correspondiente y su enlace “en vivo” para que vean cómo lo interpreta su navegador web y con click derecho (o el método adecuado) observen el código fuente, analízenlo y vuelven por estos lares. Ojito pues. 😉
  • Por supuesto debo acotar que esto último de los espacios extras para el código html ya otras personas han tenido que lidiarlo y lo han sobrellevado pero que muy bien; por ejemplo en esta página web nos hacen el trabajo: copiando , pegando y ejecutando me dice que pudo cortar 123 espacios, éso son 984 bits ahorrados, multipliquen eso por las miles o decenas de miles de visitas a su página web: bueno “éso no son conchas de ajo” como dice el refrán.

Formato básico del texto.

Ya sabemos cómo agregar títulos y párrafos en lenguaje html, ahora veremos cómo darle formato a nuestro texto, verbi gratia a lo largo de este tutorial hacemos gala de ello.

Texto en negritas:

<p>«Los Estados Unidos parecen destinados por la Providencia a plagar la América de miserias en nombre de la libertad».<br><b>Simón Bolívar.</b></p>

El pensamiento de nuestro Libertador arriba expresado en lenguaje html introduce el salto de línea para separar la cita del autor ya que debemos tener en cuenta que los navegadores hacen sólo lo que le ordenamos: todo el texto es un párrafo y así lo muestra, seguido, pero a fin de darle un sentido de relación (pensamiento-autor) se le debe insertar el comando <br> cuantas veces lo necesitemos recordando siempre que separa líneas, no párrafos.

En XHTML se debe escribir como <br />, con un espacio entre la letra erre y la barra, teniendo un así un “autocierre” pero en HTML dicho comando no tiene cierre y si le agregamos (</br> o <br/>) los navegadores lo admiten e interpretan como <br>. Yo prefiero utilizar <br /> tal y como convenimos al comienzo de este documento.

¿Recuerdan lo que hablamos sobre eliminar los espacios del texto indentado? Pues bien he de añadirles que si escribimos varios espacios entre las palabras y saltos de línea nuestro navegador web lo mostrará exactamente igual. Así el código arriba mostrado es igual a este:

<p>«Los Estados Unidos   parecen destinados por la Providencia a plagar   la América de   miserias en    nombre de la libertad».<br>


<b>Simón

1
&amp;nbsp;
Bolívar.</b></p>

Noten esas letras que agregué entre el nombre y apellido: se conoce como espacio irrompible y se utiliza para decirle al navegador que mantenga esas dos palabras unidas por un espacio sin importar ningún otro comando (centrado, justificado, etc.) y se representa como &nbsp; y observen el recurso nemotécnico: nbsp=NoBlankSPace (encerrado entre et y punto y coma tal como lo vimos para representar caracteres especiales; si lo pensamos bien es un comando de apertura y cierre no simétrico en html).

Texto en cursivas:

<i>Fuente</i>: de la carta al Coronel Campbell, Guayaquil, 5 de agosto de 1829.

Si queremos “aislar” dicho pensamiento podemos agregar una linea horizontal antes y después y no es necesario escribir una serie de guiones como estilan los editores de texto avanzados, simplemente le colocamos <hr> y para ser más preciso con su correspondiente autocierre <hr /> (tal como lo expliqué dos párrafos hacia arriba).

Texto enfatizado:

Es diferente de las cursivas (también llamadas “italics” en inglés) y nos sirve para hacer notar algo, por ejemplo fechas, tal como lo muestro:

<i>Fuente</i>: de la carta al Coronel Campbell, <em>Guayaquil, 5 de agosto de 1829</em>.

Tal vez veamos iguales a cursivas y enfatizados en nuestro navegador web. Pero hay diferencia, y aquí voy a englobar la etiqueta de negritas <b> con la etiqueta fuerte <strong>: mientras que <i> y <b> es opcional para el navegador el mostrarlo diferente, las etiquetas <em> y <strong> obligan a mostrarlo diferente.

Aún más allá, como los dispositivos electrónicos han adquirido gran poder de cálculo, eso ha permitido que incluso dichos aparatos lean en voz alta a personas discapacitadas de la vista y cuando encuentran las etiquetas <em> y <strong> el tono de voz cambia de manera correspondiente.

Texto “grande” y “pequeño”:

Encierro entre comillas los términos sólamente para que noten que dependerá del tamaño predefinido en su navegador web: en base a ese tamaño mostrará más grande o más pequeño los textos a mostrar:

<p>
  <big>«Los Estados Unidos   parecen destinados por la Providencia a plagar la América de miserias en nombre de la libertad».<br />
  <b>Simón&nbsp;Bolívar.</b></big><br />
  <small><i>Fuente</i>: de la carta al Coronel Campbell, <em>5 de agosto de 1829</em></small>.
</p>

Texto “preformateado”:

Muchas veces necesitamos, por ejemplo, escribir fórmulas matemáticas (y ya sabemos cómo insertar caracteres especiales) y por practicidad se definió este comando para que el navegador lo presente con una fuente monoespaciada y respetando los espacios y saltos de lineas sin necesidad de etiquetas especiales tal como hemos venido aprendiendo. Aquí la simplicidad es bienvenida, imaginen todo el esfuerzo en tecleo de comando para mostrar esto:

<pre>
   y =  x + 3
y -3 =  x
  -x = -y +3
   x =  y + 3
</pre>

Ese cuadro semisombreado que ven está hecho con el comando <pre> pero es el estilo aplicado en este blog lo que lo hace así, sirva como introductorio a las hojas de estilos en cascada.

Superíndices y subíndices.

De nuevo las fórmulas matemáticas son las que mayor uso dan a estas etiquetas:

<pre>
   y<sub>1</sub> =  x<sup>2</sup> + 3
</pre>

Texto resaltado:

Si queremos indicar algo importante, podemos resaltarlo (teniendo siempre en cuenta que cada navegador lo muestra a su manera prestablecida):

y = 5 - 3
<mark>y = 2</mark>

Texto insertado y eliminado:

Muchas veces queremos explicar cómo se llegó a un punto determinado agregando y eliminando explicaciones, encuentro útil siempre las fórmulas matemáticas; siguiendo con el ejemplo anterior:

y = 5 - 3
y = 5 - <ins>(+</ins>3<ins>)</ins>
y = 5 - <del>(+</del>3<del>)</del>
<mark>y = 2</mark>

Observación especial: el insertado puede confundirse con el comando subrayado <u></u>, etiqueta esta que no he explicado aún porque lo considero en desuso ya que se confunde fácilmente con los enlaces “links” en los navegadores. Tanto es así que ahora se utiliza para denotar palabras mal escritas (o en uso especial para el idioma chino); valga la acotación.

Todo lo que explico sobre formato de texto está en este enlace para que lo visualicen y analicen.

Con lo que hemos aprendido es suficiente para comenzar a escribir una página web decente, pero en camino a la excelencia debemos aprender más sobre el sueño de Tim Berners Lee: el hipertexto.

Enlaces y tipos de enlaces.

 La razón de ser del html: los enlaces que permiten guiar hacia otros contenidos, construídos unos sobres otros. Es lo que he hecho con este tutorial, los “links” que he colocado indican de dónde he obtenido información e incluso permiten profundizar los conocimientos de usted amable lector o lectora, si así lo quisiera. Sin más lo presento:

<a href="http://www.seniat.gob.ve/">Servicio Nacional Integrado de Administración Aduanera y Tributaria.</a>

Tal como pueden apreciar, tiene su apertura y cierre <a>…</a> pero además se debe incluir la dirección web (que no será visible a menos que el usuario ubique el puntero sobre el enlace) y en los tres puntos colocaremos la descripción del sitio a donde queramos referir al internauta.

Es de hacer notar que incluso podemos especificar la dirección ip del servidor a consultar (si es dedicado, es decir, sirve una sola página web) y hasta por cual puerto vamos a hacer la consulta. El siguiente ejemplo nos permite preguntarle al Instituto Nacional de Higiene “Rafael Rangel”, ente que tiene en Venezuela el monopolio sobre la aprobación o negación de nuevos medicamentos o la renovación de los mismos, sobre los medicamentos vigentes cuyos nombre comiencen con la letra hache:

<a href="http://190.202.114.146:7474/ef/aprobados_int/productos-1.php?l=H">Medicamentos aprobados en Venezuela, letra H.</a>

 Por el contrario, si lo que queremos es referirnos a una página web que está en nuestro mismo servidor y en la misma carpeta lo que debemos hacer es simplemente colocar el archivo que contiene la página web:

<a href="ejemplo.html">Ver ejemplo</a>

Para que cambiemos la búsqueda por defecto en nuestro propio servidor web sólo debemos colocar el comando <base> el cual explicamos brevemente y ahora vamos a ampliar:

<head>
<base>href="http://www.ks7000.net/images/"</base>
</head>

Siendo así que este comando <base> esté declarado en <head> por defecto el penúltimo enlace de ejemplo será buscado en el dominio “ks7000.net” en la carpeta “images” en vez de la carpeta donde está alojada la página abierta.

Otra opción muy útil es especificar si el enlace se abrirá en la misma ventana o pestaña de donde se le llama o en una nueva, aquí en este tutorial las he colocado en una nueva ventana o pestaña para poder seguir el hilo del tema principal de estudio. Así el comando que necesitamos es:

<a href="http://www.ivss.gob.ve" target="_blank"></a>

El otro valores para target es “_self”, que es el valor por defecto y generalmente no se escribe (“_parent”, “_top” y “framename”, que se usaban con frame –no  soportado por HTML5- dejaron de usarse). El comando <base> también acepta ambos parámetros.

 Imágenes.

La inclusión de imágenes en una página web pasa por hablar brevemente sobre la historias de los formatos utilizados para representarlas. Pero primero veamos el comando utilizado por HTML para decirle al navegador cual imagen debe “cargar” y luego ahondaremos el tema de la historia de las imágenes digitales:

<img src="mi_imagen.jpg" alt="Mi imagen" />

Como ven el comando no tiene un cierre sino más bien un autocierre (opcional en HTML pero obligatorio en XHTML). En este ejemplo asume que la imagen está alojada en la misma carpeta que contiene el archivo .html (a menos que usemos el comado <base>, visto anteriormente dentro de <head>). Si la imagen estuviera ubicada en una subcarpeta, simplemente colocaríamos:

<img src="/images/mi_imagen.jpg" alt="Mi imagen" />

O incluso, si estuviera ubicada en otro servidor de nuestra propiedad (por favor eviten el hotlinking ya que es de muy mal gusto “robar” el ancho de banda a otros entes o personas):

<img src="http://www.ks7000.net/images/mi_imagen.jpg" alt="Mi imagen en otro servidor" />

El parámetro alt es obligatorio ya que el navegador muestra el texto colocado entre comillas mientras descarga la imagen en sí y si no la puede descargar, pues bueno, el texto indica que allí debería ir una imagen. Otro uso importante es para los discapacitados visuales ya que los programas lectores usan este texto para narrar de que imágen se trata, así que ojito con colocarle acertadas palabras.

Un uso muy común para las imágenes es utilizarlas como botones para los enlaces ya que llaman más la atención que un mero texto subrayado, aquí debemos aplicar el anidado de instrucciones, fíjense:

<a href="www.a.com"><img src="mi_imagen.jpg" alt="Mi imagen" /></a>

Otro parámetro que soporta el comando <img> es <style> con el cual podemos especificarle al navegador web del usuario que la imagen deseada la convierta a un tamaño específico, ancho y alto en pixeles, por ejemplo:

<img src="/images/mi_imagen.jpg" alt="Mi imagen" style="width:128px;height:128px" />

Así, no importa el tamaño que tenga la imagen original, ésta será mostrada a 128×128 pixeles pero debe usarse esto con mucho cuidado: tengan presente que la imagen que descargará el usuario siempre ocupará el mismo ancho de banda, NO IMPORTA QUE SE VEA MÁS PEQUEÑA, la cantidad de bytes descargados siempre será la misma cantidad. Es por ello que ahora si hablaré de la historia de las imágenes digitales, tómense un café y vuelvan que esto se pone interesante. 😎


style=”text-align: justify;”>Imágenes digitales.

En el siglo pasado, cuando usamos rollos fotográficos (plásticos impregnados de químicos fotosensibles para fijar la luz, generalmente hechos a base de plata) quedaban como negativos fotográficos con los cuales se podían sacar las fotografías en sí, cuantas copias se necesitaran. Con las fotografías digitales sucede un proceso parecido: cada cámara o filmadora almacena la foto original en formato RAW o DCRAW que, esencialmente, consiste en millones de ceros y unos que representan los colores que recibió el sensor digital. Es, por tanto, muy grande y tiene muy poca pérdida de información sobre la fotografía tomada. Pero al igual que con los negativos fotográficos, esta información poco nos sirve por su dificultad de visualizarlos con el ojo humano. Es por ello que, para ahorrar en hardware, se decidió someter dichos datos RAW (existen cientos de formatos RAW, cada fabricante usa o inventa el que mejor le parece y la mejor alternativa a futuro es el formato libre DCRAW) a un proceso de pérdida de información y además compresión y codificación en un formato estandar para, de esta manera, poder compartir con el resto del mundo la fotografía tomada.

DCRAW: live free or die.
DCRAW: live free or die.

Es decir, nuestros navegadores web deben ser capaces de mostrar cualquier imagen siempre y cuando dicho fichero esté codificado en un formato normalizado, el formato RAW o DCRAW no nos sirve para este propósito de hacer páginas web. Simplificando: un programador de paginas web debe rápidamente hacerse estas preguntas antes de escoger un formato de imagen para el trabajo por el cual lo contrataron:

  • ¿Necesita transparencia?
  • ¿Necesita animación?
  • ¿Necesita buena calidad de imagen?

 

Lo que paso a enseñar es un resúmen al máximo de lo publicado (en idioma inglés) de las siguientes páginas:


Si tenemos en cuenta que las imágenes en una página web en promedio ocupan entre 60 y 70% del tamaño en bytes de la misma debemos prestar especial atención en escoger los formatos de imágenes correctos para ahorrar al usuario tiempo, dinero en conexión, y se queden más de un minuto en nuestro sitio web.

Fuentes consultadas.

En idioma inglés.