PHP Simple HTML DOM Parser

Download PDF

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!

Continue reading

Download PDF

PHP y cURL

Download PDF

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:
[cc lang=”php” tab_size=”2″ lines=”80
[/cc]

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:
[cc lang=”php” tab_size=”2″ lines=”80″ widht=”10%”]
$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
“;
}
} else {
echo “No se pudo inicializar PHP curl.
“;
}
?>[/cc]

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:

[cc lang=”php” tab_size=”2″ lines=”80″ widht=”10%”] $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
“;
}
} else {
echo “No se pudo inicializar PHP curl.
“;
}
?>[/cc]
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:
[cc lang=”php” tab_size=”2″ lines=”80″ widht=”10%”] $objCurl = curl_init(“http://www.soporteweb.com/”);
if ($objCurl == false) {
print “No se pudo inicializar PHP curl.
“;
} else {
$nom_arch = ‘PHP_curl.html’;
$arch = fopen( $nom_arch , “w”);
if ($arch == false ) {
print “No se pudo abrir el archivo ‘”.$nom_arch.”‘
“;
curl_close ($objCurl);
} else {
$resp = curl_setopt ($objCurl, CURLOPT_RETURNTRANSFER, 1);
if ( $resp == false ) {
print “No se pudo establecer CURLOPT_RETURNTRANSFER.
“;
curl_close ($objCurl);
} else {
$resp = curl_setopt ($objCurl, CURLOPT_FILE, $arch);
if ( $resp == false ) {
print “No se pudo establecer CURLOPT_FILE.
“;
curl_close ($objCurl);
} else {
$resul = curl_exec ($objCurl);
if ($resul == false) {
echo “No se pudo ejecutar PHP curl.
“;
} else {
print “El archivo fue guardado con el nombre ‘PHP_curl.html’.
“;

// curl_close NO devuelve resultado:
curl_close ($objCurl);
}
}
}
}
}
?>[/cc]

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):


  $objCurl = curl_init("http://www.soporteweb.com/")
    or exit("No se pudo inicializar PHP curl.
");

$nom_arch = ‘PHP_curl.html’;
$arch = fopen( $nom_arch , “w”)
or exit(“No se pudo abrir el archivo ‘”.$nom_arch.”‘
“);

curl_setopt ($objCurl, CURLOPT_RETURNTRANSFER, 1)
or exit(“No se pudo establecer CURLOPT_RETURNTRANSFER.
“);

curl_setopt ($objCurl, CURLOPT_FILE, $arch)
or exit(“No se pudo establecer CURLOPT_FILE.
“);

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

print “El archivo fue guardado con el nombre ‘PHP_curl.html’.
“;

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

¡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:

[cc lang=”php” tab_size=”2″ lines=”80″ widht=”10%”]curl_setopt($objCurl, CURLOPT_FTPLISTONLY, 1)
or exit("No se pudo establecer CURLOPT_FTPLISTONLY");
[/cc]

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");[/cc]
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:
[cc lang="php" tab_size="2" lines="80" widht="10%"] echo curl_error($objCurl);[/cc]
https://twitter.com/souzace/status/868869012414840832

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“):


  var_dump($_POST);
?>[/cc]

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


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

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);
?>[/cc]
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.

[cc lang=”php” tab_size=”2″ lines=”80″ widht=”10%”] //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”);[/cc]

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.


  $ObjCurl = curl_init()
    or exit("No se pudo inicializar PHP curl.
");

curl_setopt ($ObjCurl, CURLOPT_URL, “http://www.soporteweb.com”)
or exit(“No se pudo establecer la URL.
“);

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

$verbose_arch = fopen(‘verbose.txt’, ‘a’);
curl_setopt($ObjCurl, CURLOPT_STDERR, $verbose_arch)
or exit(“No se pudo establecer CURLOPT_STDERR
.”);

curl_exec ($ObjCurl)
or exit(“No se pudo ejecutar PHP curl.
“);

curl_close ($ObjCurl);
?>[/cc]

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');[/cc]

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.

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");[/cc]

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.


  $objCurl = curl_init()
    or exit("No se pudo inicializar PHP curl.
");

$verbose = fopen(‘verbose.txt’, ‘a’)
or exit(“No se pudo abrir el archivo verbose.txt
“);
$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.
“);

curl_close ($objCurl);
?>[/cc]

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:


  $objCurl = curl_init()
    or exit("No se pudo inicializar PHP curl.
");

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
“);
$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.
“);

curl_close ($objCurl);
?>[/cc]

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[/cc]

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:


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

$nom_arch = ‘servidor.html’;
$arch = fopen( $nom_arch , “a”)
or exit(“No se pudo abrir el archivo ‘”.$nom_arch.”‘
“);

curl_setopt ($objCurl, CURLOPT_RETURNTRANSFER, 1)
or exit(“No se pudo establecer CURLOPT_RETURNTRANSFER.
“);

curl_setopt ($objCurl, CURLOPT_FILE, $arch)
or exit(“No se pudo establecer CURLOPT_FILE.
“);

curl_setopt ($objCurl, CURLOPT_CONNECTTIMEOUT, 7)
or exit(“No se pudo establecer CURLOPT_CONNECTTIMEOUT.
“);
curl_exec ($objCurl)
or exit(“No se pudo ejecutar PHP curl.
“);

$nom_arch = “servidor_respuesta.txt”;
$archivo = fopen($nom_arch, “a”)
or exit(“No se pudo abrir el archivo'”.$nom_arch.”‘
“);

$resp = curl_getinfo($objCurl)
or exit(“No se pudo obtener información de la ultima conexion.
“);

fwrite($archivo, serialize($resp))
or exit(“No se pudo escribir en el archivo ‘”.$nom_arch.”‘
“);

fclose($archivo)
or exit(“No se pudo cerrar el archivo ‘”.$nom_arch.”‘
“);

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

[/cc]

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.

Futuro de cURL.

Como bien es sabido por todos nosotros, Internet como tal está basado en las siete capas de red según el modelo de interconexión de sistemas abiertos (ISO/IEC 7498-1), más conocido como “modelo OSI”, (en inglés, Open System Interconnection) y cURL hace uso de la séptima capa para las transferencias por internet orientadas a ficheros. Por ello su autor Daniel Stenberg deja bien claro que eso es lo que seguirá haciendo cURL ahora y durante mucho tiempo. A continuación una traducción automatizada de su entrada en el blog al respecto:

No soy de los que pasan el tiempo mirando hacia el horizonte soñando con la grandeza futura y haciendo planes sobre cómo ir allí. Trabajo en cosas ahora mismo para trabajar mañana. No tengo idea de lo que haremos y trabajaremos en un año a partir de ahora. Conozco un montón de cosas en las que quiero trabajar a continuación, pero no estoy seguro de si alguna vez llegaré a ellas o si realmente enviarán o si tal vez serán reemplazadas por otras cosas en esa lista antes de que llegue a ellas.
El mundo, Internet y las transferencias cambian constantemente y nos estamos adaptando. No hay sueños a largo plazo más que apegarse al plan simple y único: hacemos transferencias de Internet orientadas a archivos utilizando protocolos de capa de aplicación.
Las estimaciones aproximadas dicen que ya podemos tener mil millones de usuarios. Lo más probable es que si las cosas no cambian demasiado drásticamente sin que podamos mantener el ritmo, tendremos incluso más en el futuro.

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.

<Esto es todo, pora ahora>.


Actualizado el sábado 27 de enero de 2018.

Recientemente, pocos días atrás, el creador de cURL, Daniel Stenberg, publicó la versión 7.58 la cual contiene una curiosa correción al proceso de agregar un “espacio en blanco” (sí, un simple y vulgar espacio en blanco) en el “pase” de las cabeceras URL (ver en GitHub el causante de este desaguisado) lo cual nos parece muy significativo, pues somos de los que insistimos y somos fastidiosos en corregir hasta el último caracter al programar (si véis algún error por estos lares hacednos un comentario abajo). Pero no somos los únicos, mirad el siguiente “tuit”:


Fuentes consultadas.

En idioma castellano.

En idioma inglés.


Download PDF

PHP tutorial

Download PDF

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.

Continue reading

Download PDF
apache2 htacces

Mejorando la seguridad en Apache2 .htaccess

Download PDF

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

Continue reading

Download PDF
Apache mod_rewrite

Tutorial para configurar mod_rewrite en Apache sobre Ubuntu

Download PDF

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:

sudo nano /var/www/html/.htaccess

Y le agregamos una sola línea:

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”):

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 ).

sudo nano /var/www/html/.htaccess

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

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:

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.

Fuentes consultadas:

En idioma castellano:

En idioma inglés:

Enlaces hacia expresiones regulares:

En idioma japonés:

 

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

Mozilla Firefox Reader View.

Download PDF

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. Continue reading

Download PDF

GNU Linux Turnkey 14.

Download PDF

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!>.

Download PDF

Cambiar refresco de pantalla en Debian.

Download PDF

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?).

Download PDF

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

Download PDF

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>.

Download PDF

Curso básico de HTML 5.

Download PDF

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.

Continue reading

Download PDF