Archivo de la categoría: Uncategorized

Comprimir la salida de un php

Cuando hacemos una página en php, normalmente la solemos hacer para que muestre contenido de texto ya formateado (en html si es para un navegador, en xml si es para un servicio web, etc). Cuando digo formateado me refiero a que no solo contiene contenido textual, sino que también contiene etiquetas de formato, etiquetas pertenecientes al tipo de documento, comentarios, códigos, etc. Esto al final provoca que haya mucha saturación en cuanto a contenido, o dicho de otra forma, se envían muchos bytes.

El problema radica en que por un lado se esta gastando un ancho de banda que pudiera servir para otras cosas (como es el caso de los hosting, donde tiene un limite de transferencia mensual) y al mismo tiempo provoca que se tarde más tiempo en descargar esa información (especialmente si estamos hablando de modems).

La solución pasa por comprimir la salida del php y que el navegador del cliente se encargue de descomprimirla. Para ello hace ya tiempo que se añadió al estardar HTTP 1.1 la cabecera Accept-Enconding. Esta cabecera es enviada por el navegador al servidor web y contiene una lista de métodos de codificación de contenido que el navegador puede tratar. En el caso del Firefox o del Internet Explorer esta lista es gzip y deflate. El gzip es el método que nos interesa, ya que con el, se comprime la salida. Así que si el navegador pide al servidor un página php (y esta permite comprimirla como veremos a continuación), el documento que el servidor entrega al navegador estará comprimido (con una cabecera a su vez denominada Content-Encoding), con el consecuente ahorro de tiempo de transferencia y cantidad de datos a transmitir. Teniendo en cuenta que casi siempre suele ser texto lo que se envía, la compresión se hace mucho mejor, ya que se repite mayor cantidad de carácteres.

Ejemplo de petición del navegador Firefox:
GET /divisas/divisas.php HTTP/1.1
Host: www.quejateportodo.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; es-AR; rv:1.7.5) Gecko/20041108 Firefox/1.0
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: es-ar,es;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive

Ejemplo de petición del navegador Internet Explorer:
GET /divisas/divisas.php?idioma=es&fecha=09/04/2005&version=201&codigo=21988 HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
Host: www.quejateportodo.com
Connection: Keep-Alive
Cookie: PHPSESSID=09b4f65e7adf47e857a309d5a9ef83e3

A lo que en mi caso el servidor devuelve esta respuesta similar en ambos casos:

HTTP/1.1 200 OK
Date: Sat, 09 Apr 2005 16:49:14 GMT
Server: Apache/1.3.33 (Unix) mod_gzip/1.3.26.1a mod_auth_passthrough/1.8 mod_log_bytes/1.2 mod_bwlimited/1.4 PHP/4.3.10 FrontPage/5.0.2.2635 mod_ssl/2.8.22 OpenSSL/0.9.7a
X-Powered-By: PHP/4.3.10
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Last-Modified: Sat, 09 Apr 2005 16:49:14 GMT
Cache-Control: post-check=0, pre-check=0
Content-Encoding: gzip
Vary: Accept-Encoding
Content-Type: text/xml
Age: 496
Connection: close

Y después de tanta teoría, la práctica:

<?
ob_start(«ob_gzhandler»);

… Aquí se mete toda la lógica del php …

ob_end_flush();
?>

¿A que resulta muy curioso que sea tán extremadamente sencillo el hacerlo?. Primero ponemos al principio del todo de la página php la instrucción ob_start del php, que sirve para activar el modo «buffering», que no es otra cosa que primero genera la página y luego la envia en vez de irla enviando a medida que se va generando. Hay que pasarle el parámetro de texto ob_gzhandler para que al final comprima todo lo que tiene en el buffer antes de enviarlo. Finalmente ponemos ob_end_flush al final del todo de la página php, que sirve para cerrar el buffer y enviarlo todo.

Y para terminar, solo deciros que lo useis, ya que os supondrá un ahorro bastante efectivo. Si quereis comprobar si lo teneis instalado en vuestro servidor, buscad las librerias zlib, zend y la variable output_buffering a 1 en un phpinfo.

Otro sistema más para combatir el antispam

Hace ya tiempo que le estuve dando vueltas a como combatir el spam de una vez por todas…

Es de sobra conocido que los filtros anti-spam tienen dos defectos, por un lado filtran muchas veces correos spam como legítimos, y viceversa, correos que estamos esperando no los recibimos porque el filtro los considera spam.

La solución de tener listas negras de ips (los dominios no sirven porque los spammers pueden poner el que quieran como remitente) no es en absoluto fiable, ya que por ejemplo un usuario puede enviar spam desde una linea adsl (ya sea conscientemente o sin saber que esta infectado por un troyando o virus) y al ser ip dinámica, otro usuario que la tome posteriormente no podrá enviar emails; o aún peor, meter a todo un rango de ips en una lista negra (como pasó con telefonica) y fastidiando a todos los usuarios de ese ISP que quieran enviar emails.

El sistema que hace google (y desarrollado por yahoo) de firmar los emails esta bién, pero aún no esta implantado masivamente y tardará aún mucho que todos los programas servidores y clientes de SMTP lo implanten (y peor aún cuando Microsoft no lo tome como estandar y se invente el suyo propio).

Mi solución, a falta de cubrir ciertos aspectos técnicos se presenta en el siguiente diagrama:

Básicamente consiste en pedir confirmación de los emails a su remitente antes de tomarlos como buenos en futuras ocasiones. Faltarían detalles como listas de correos o publicidad requerida, pero este sistema funcionaría con la tecnología actual y funcionaría como puente entre el servidor POP3 y el cliente de correo.

¿Buscas un código fuente?

Pues en www.koders.com seguramente encuentres algo parecido a lo que estés buscando. Se trata de un buscador de código fuente donde como criterios de busqueda puedes filtrar por lenguaje de programación o licencia de uso del mismo. La única pega es que para encontrar lo que andabas buscando tengas que leer un chorro de codigo de otra persona que tenga una forma curiosa (horrible) de hacer las cosas, cosa por la cual ya he tenido que pasar en algún que otro trabajo donde he estado :).

Configurar Linux como Router

Recientemente he adquirido un ordenador de 2º mano en mi empresa. La utilidad que le voy a dar es la de tener un ordenador en la casa donde voy de veraneo en Cercedilla. Pero claro, durante estos días lo he estado configurando y metiendole todos los programas necesarios y los que preveía que tarde o temprano usaré. Con este ya suman 4 los ordenadores que tengo, a saber:

Servidor: VIA EPIA 800, 128 MB RAM, linux

Uso diario: AMD XP, 2.4 Ghz., 512 MB RAM, 280 GB HD, linux, windows xp

Portatil: AMD XP Mobile, 2.4 Ghz, 512 MB RAM, 40 GB HD, windows xp

Nueva adquisición: Pentium IV 2.4 Ghz, 768 MB RAM, 20 GB HD, windows xp

Pues con estos equipos el otro día se me ocurrió hacer dos redes, una del tipo 192.168.0.0/24 y otra del tipo 10.0.0.0/8 que estuviesen unidas al nuevo equipo, actuando este como router. En la red 192* tenía el ordenador de uso diario y el router ADSL, y en la red 10* tenía al portatil. Mi intención era que todos los ordenadores se vieran entre si y también tuviesen acceso a Internet. El ordenador nuevo tenía dos tarjetas y corría el linux knoppix. Una tarjeta tenía la ip 10.0.0.254 y la otra tenía la ip 192.168.0.4. En linux ambas se configuran así a través de la shell o linea de comandos:

ifconfig eth0 192.168.0.4 netmask 255.255.255.0 up

ifconfig eth1 10.0.0.254 netmask 255.0.0.0 up

En este ordenador, la puerta de enlace o gateway estaba configurado para 192.168.0.254, o lo que es lo mismo, la ip que tiene mi router ADSL:

route add default gw 192.168.0.254

El portatil y el ordenador de uso diario ejecutaban windows xp y tenian como ip 10.0.0.1 y 192.168.0.1 respectivamente. El portatil estaba conectado a un switch (con puerta de enlace 10.0.0.254) al igual que una de las tarjetas del ordenador nuevo; el ordenador de uso diario estaba conectado al router ADSL (como es un hub al fin y al cabo; con puerta de enlace 192.168.0.254) al igual que la otra tarjeta del ordenador nuevo.

Una vez ya todo conectado puse en el linux del ordenador nuevo esta sentencia desde la shell:

echo «1» > /proc/sys/net/ipv4/ip_forwarding

que permitia reenviar los paquetes tcp/ip por las redes que tenia acceso este ordenador (se puede ver poniendo un simple route en linux)

Pero hay triste de mi que los ordenadores host no se veian entre ellos, ya que haciendo ping de uno a otro no se veian, sin embargo si veian al ordenador nuevo, aunque curiosamente si veían al router y también podían navegar por Internet (en ambos estaban puestas ya las DNS correctas), por lo que pensé que algo había hecho mal. Asi que pensando, pensando, cambié la puerta de enlace del ordenador de uso diario que estaba como he comentado antes a 192.168.0.254 a 192.168.0.4 y ¡¡¡ voila !!! ya se veían entre ellos. Había creado dos redes con casi nada de esfuerzo. Luego ya me entretuve con el iptables para configurar accesos desde el shell como:

iptables -A FORWARDING -p tcp –destination-port 80 -j DROP

que no permite el paso de paquetes por el puerto http o

iptables -A FORWARDING -s 192.168.0.0/24 -d 10.0.0.0/8 -j DROP

que no permite el flujo de daots entre una red y otra.

El dibujo de la red sería tal que así:

y muestra como aunque el ordenador de uso diario y el router ADSL estan en la misma red, los paquetes entre uno y otro deben pasar por el ordenador nuevo.

Transparencias con Windows y GDI en Visual Basic

En el trabajo me surgió la problematica de hacer que una imágen tenga un grado de transparencia sobre otra. Esto, aunque parezca una trivialidad, no lo es puesto que aunque la solución original es generar una mascara para hacer la transparencia, el permitir que existan varios grados lo complica un poco. Sin embargo al final he conseguido compactarlo todo en un procedimiento para que pasandole como parametros el dispositivo de contexto de origen, el dispositivo de contexto de destino (y donde se almacenará el resultado de la transparencia), las dimensiones de la imagen (en mi caso suelo poner las dimensiones en pixeles del picturebox) y el grado porcentual de transparencia, se genera de un modo casi inmediato el efecto deseado. Aqui os dejo el código:

Actualización 07/07/2005:
El código de aquí arríba es más limitado de lo que yo pensaba y hace cosas que no debiera, por lo que hoy que hemos estado probandolo lo hemos descartado y en su lugar he encontrado algo mucho más sencillo… La función AlphaBlend de la API de windows 98, Me, 2000 y XP:

Primero colocais en la variable número un valor entre 0 (transparente) y 255 (opaco) para definir el nivel de transparencia de la imagen origen con respecto a la de destino, posteriormente con una sencilla formula (no os calenteis mucho la cabeza, ya que es una regla nemotécnica para darle un valor) se saca el valor a pasar al último parámetro de la función. Luego ya en la función le pasais el hdc de destino, el punto x e y del empiece a trabajar del destino y el ancho y alto del destino, posteriormente los mismos parámetros pero esta vez los del origen.

Funciona bastante bién y estará en todos los windows modernos.

A tortas con el MFC y los cursores e iconos

Bueno, hoy he estado haciendo pruebas sobre como crear un control estático donde maneje a mi antojo lo que dibuje en el con MFC para windows, y entre otras cosas se me ha ocurrido meterle un icono como dibujo y que cuando el ratón pase por una zona del control se cambie el cursor (el puntero).

Para el primero he tenido varios problemas puesto que no esta muy depurada la API de windows para manejar cursores y dejarlos en 16×16 pixeles, haciendo cosas raras, menos mal que dentro del oceano de Internet uno puede ir recopilando informaciones cuando no se encuentra todo en un documento para saber como hacerlo. Tan sencillo como esto:

Primero cargo el icono con la función LoadImage, donde le paso como parámetros la instancia de la aplicación donde se encuentra el icono (la misma aplicación donde se ejecuta), el identificador del recurso del icono pasado a cadena con la macro MAKEINTRESOURCE, el tipo de imagen que es (un icono), la anchura y la altura del mismo y finalmente que lo coja con los colores por defecto.

Segundo dibujo el icono en el dispositivo de contexto que nos ofrece windows para dibujar en el control CStatic, no uso la función DrawIcon del objeto de dispositivo contexto por que no consigue adaptar bién el icono a 16×16 pixeles, por lo que uso la función win32 DrawIconEx que si me lo permite, pasandole como parámetros el manejeador del dispositivo de contexto, la posición x e y donde quiero dibujar el icono, el icono, su achura y altura, ningúna brocha (no es necesario) y le digo que es una imagen con transparencias (DI_NORMAL indica todo eso).

Tercero lo destruyo porque en esto de la programación en C es bueno la «limpieza».

Para el segundo caso, siendo aún más sencillo me he partido más los cuernos, simplemente porque el evento que se debe usar para cambiar el cursor no tiene mucha lógica con lo que uno quiere hacer. Mi idea es que cuando moviese el ratón por una zona del CStatic, se cambiase el cursor, sin embargo usando el evento OnMouseMove no funciona para nada la función SetCursor. He de decir que cuando digo CStatic, en realidad es una clase que he derivado de esa para poder interceptar los eventos. Por lo visto para que funcione lo que queremos hacer debemos usar el vento OnSetCursor, que funciona a semejanza del OnMouseMove, pero que no te da las coordenadas dentro del control donde se encuentre el puntero del ratón, sino que se activa cuando se pasa el ratón por el control. Esto no funcionaría si no tuviesemos activado la opción «notify» de los estilos del control. Aquí dejo mi solución de como lo he conseguido al final:

Primero declaro una variable POINT, luego pregunto con GetCursorPos que me diga la posición relativa a pantalla donde se encuentra el ratón, y a continuación lo transformo a coordenadas del control gracias a la función ScreenToClient. Con todo esto logramos saber en que posición de nuestro control esta el cursor ya que el OnSetCursor no nos la da como parámetro como lo hicera el OnMouseMove.

Segundo comparo si el cursor esta dentro de un rango en el eje de la altura y si es así ya uso la función SetCursor (de la api de win32 no del objeto), pasandole como parámetro el cursor que me devuelve la función LoadCursor, a la cual se le pasan como parámetros la instancia donde se encuentra el cursor (la nuestra en este caso) y el identificador del cursor pasado a cadena con la macro explicada antes. Después salimos de la función delvolviendo un valor TRUE indicando que no hay que hacer nada más.

Tercero, si llega hasta aquí significa que no ha pasado por el if y que llama al manejador por defecto devolviendo el valor que a su vez este devuelve, esta linea la incorpora automáticamente el Editor de Visual C++ cuando añadimos el evento OnSetFocus.

Como veis la programación de Windows es apasionante, pero muchas veces me encuentro con cosas que no funcionan como deben o se manejan de forma ilógica, pero bueno, menos mal que ya hay mucho escrito sobre eso. Por cierto, sigo pendiente de aprender programar linux, estoy por el capítulo de programación avanzada de ficheros y en siguiente ya son los demonios, y aún así me queda mucho libro por leer 🙂

Navegación anónima

Después de las vacaciones de verano ya va siendo hora que postee de nuevo en el blog, aunque me da a mi que nadie o casi nadie lo lee, pero bueno, aquí estamos.

Muchas veces hemos navegado por Internet con nuestro navegador favorito y sabemos que vamos dejando nuestro rastro allá por donde vamos, o bién queremos opinar en algún foro como una persona distinta, o bién queremos votar más de una vez en alguna votación, mandar un correo electrónico y que no se sepa el origen, etc etc etc.

Pues bién, la solución a todos estos problemas son los proxys abiertos, los cuales son proxys mal configurados por administradores o usuarios particulares que los tienen para compartir una conexión a Internet y por tanto cualquiera puede usar ese mismo proxy desde fuera de la red donde se encuentra.

Configurando la conexión en nuestro navegador web para que pase a través de un proxy abierto, se elimina la ip que poseemos y se sustituye por la ip del proxy (en algunos casos se pasa como cabecera de la petición a la página con lo que no se elimina del todo), pudiendo asi interactuar con la web que hayamos visitado sin que sepa realmente quienes somos (normalmente no se sabe quienes somos, y menos si tenemos ip dinámica, pero con esto se dobla el anonimato en la navegación).

Se puede acceder a ftp, http, https desde un proxy (siempre que este configurado para permitirlo) y conectarnos a otros puertos si usamos la tecnología SOCKS v4 o v5 (igualmente debe estar configurado para permitirlo), con lo que prácticamente se

puede hacer de todo en internet a través de un proxy. Es más, si estas en tu empresa y te capan todos los puertos menos el puerto 80 para salir a Internet, con un proxy podrás acceder al resto de puertos sin mayor peoblema.

Hay muchas listas de proxys abiertos por Internet, yo suelo usar Open Proxies, pero hay muchas listas más o menos públicas para llevar a cabo tu intimidad y anonimato.

Programación TCP/IP

Creo que a estas alturas todo el mundo sabe que es internet, y lo que aporta a la comunidad, lo que no creo que sepa tanta gente es que como la información se transmite y como hace para llegar a su destino sin errores, diferenciando tantos servicios como existen en internet y demás. Dentro de este último grupo seguro que también hay gente que además de saber lo que son los protocolos TCP e IP, les gustaría saber qué pasos seguir para programar un cliente o un servidor de red para Internet o para intranets basadas en TCP/IP. Pues bién, hay una guia estupenda llamada Beej’s Guide to Network Programming que te explica todo lo que tienes que saber para empezar a programar sockets, que no son otra cosa que los descriptores de «fichero» para la red. Tiene traducción al castellano y además, aunque esta orientado a sistemas linux/unix, también te explica como hacerlo en windows. Yo ya hice mis pinitos hace tiempo con esta guia, y entre otras cosas hice este juego para windows del conecta 4 para dos jugadores (tiene sus bugs escondidos, asi que no le trateis mal 🙂

Futuro proyecto

No se si os habeis dado cuenta ya que me gusta experiementar con tecnologías sms y email. Pues bién, mi futuro proyecto es crear un gateway email/sms/email, el cual alguien puede enviar un mensaje desde cualquier móvil al celular del gateway con el formato <dirección de email> <mensaje>, por lo que enviará ese mensaje a la dirección de correo que se solicita. Para el proceso contrario, se debe meter el número de teléfono en el asunto y el texto en el cuerpo del mensaje, con lo que se enviará ese texto al número de teléfono que se indica.

De momento lo estoy desarollando, sin embargo tengo una utilidad instalada en mi servidor linux particular (http://www.sistemasorp.com) llamada smstools que es capaz guardar los mensajes entrantes de un movil conectado por el puerto serie en una carpeta denominada incoming, como de enviar los mensajes que se encuentren en una carpeta denomiada outgoing al mismo.

La idea es que tenga un demonio corriendo bajo linux que sea quien lea la cuenta de correo habilitada a tal efecto (sms@sistemasorp.com) enviando el sms si el email es correcto, y que a su vez comprueba la carpeta incoming para enviar el email si el sms es correcto.

De momento tengo que aprender un poco más de programación en linux para hacer demonios y demás cosillas, espero que pronto este finalizado este proyecto para que podais disfrutarlo.

Edición 31/7/2004:

Buscando cosas por internet me he encontrado los mailtuils, que es básicamente una serie de utilidades y librerias para lidiar con el correo. A mi me viene de perlas, porque así puedo recoger los mensajes, interpretar las cabeceras MIME del mensaje, enviar emails, etc. desde el código de la aplicación, y sin tener que hacer llamadas al sistema a «mail» y similares como tenía pensado. Ahora solo me queda ponerme con la programación de demonios en linux para tener a punto el gateway.

Envio de sms con cualquier remitente

Y ya puestos después de publicar el anterior artículo, os comentaré como enviar mensajes SMS con un remitente cualquiera. Esta posibilidad es aún más creible que los correos electrónicos, puesto que cuando un usuario de móvil recibe un mensaje de texto en su móvil, creerá que el remitente del mismo es quien le ha enviado tal mensaje, ya que la

gran mayoría no sabrá que los sms se pueden falsificar.

Esto no es como lo del e-mail, es costoso: Si os haceis una cuenta en www.truesenses.com y comprais una cantidad de mensajes, su interfaz te permite poner además del destinatario y el mensaje, el remitente del mismo. Por lo que puedes poner como origen cadenas de texto o ún número de móvil (cuando el destinatario reciba el mensaje si tiene ese número en la agenda le aparecerá con el nombre con el que lo hubiera guardado).

Así de sencillo, 300 mensajes cuestan unos 30 euros, sin embargo al ser un operador suizo y al hacer roaming, cuando se envía un mensaje a España se cuenta como si hubieras enviado 2.

Sin embargo, y por tiempo limitado, aquí os dejo un formulario donde podreis probar este tipo de característica. Que os divirtais.

Remitente (una cadena o número internacional de móvil de 12 caracteres como máximo)
Destinatario (un número internacional de móvil de 12 caracteres como máximo)
Mensaje (130 caractéres máximo)

Edición 06/08/2004:

Después de haber tenido el servicio levantado durante 1 mes y 15 días aprox. lo cierro con la satisfacción de que ha sido una gran experiencia para todos los que lo han usado con cerca de 160 mensajes enviados desde este formulario. Quién sabe, a lo mejor me animo y lo vuelvo a activar desde www.sistemasorp.com (no lo probeis ya que tiene el movil sin batería)