Enero 23, 2009

CodeIgniter + CSS: hojas de estilo que no se cargan en IE7

Durante el último mes he estado trabajando en una aplicación web desarrollada con CodeIgniter. He ido testeando cada funcionalidad escrupulósamente tanto en IE7 como Firefox3, y todo encajaba. Todo menos la aplicación de los estilos CSS

Los estilos están guardados en un archivo externo, se importan a una view de CodeIgniter, que luego se  incluye en cada página. Este es el código de inclusión de la hoja de estilos:

<link rel="stylesheet" type="text/css" href="<?php echo base_url();?>css/main.css" />

Por alguna razón, todo esto funcionaba perfectamente en Firefox, pero no así en Internet Explorer, donde sólo se cargaban algunos estilos, teniendo que actualizar la página con F5, para que ahora sí, se cargaran todos los estilos. Sé que esto suena raro -de hecho, lo es- pero no miento.

Dado que tenía cosas más importantes de qué ocuparme fuí dejando la solución de este incómodo problema para el futuro. Ahora que toca instalar la aplicación al cliente, me he visto obligado a ponerme serio, y en un momento de inusual inspiración,  seguramente provocada por la morriña  “viernes, 5 de la tarde”, he probado a cambiar el método de inclusión por este otro:

<style type="text/css">
@import "<?php echo base_url();?>css/main.css";
</style>

Para mi sorpresa, esto ha solucionado el problema.

En fin, le dejo el sesudo análisis del porqué de todo esto a personas más  sabias que yo…

Por mi parte, me limito a dejar humilde testimonio, por si le sirviera a alguien, … y  a desearos un buen fin de semana!

Enero 20, 2009

EasyPHP: problema con acceso remoto

Instalé en un Windows el pack EasyPHP para alojar una aplicación web, y me encontré con el problema de que no podía acceder de manera remota al servidor Apache.

En algunos foros encontré posts sobre el tema. En su mayoría recomiendan la correcta configuración del firewall y el router. Pero en mi caso no era el problema.

Finalmente di con la solución, al menos en mi caso. Modifiqué el archivo de configuración de Apache, en mi instalación en c:/easyphp/ conf_files/httpd.conf, añadiendo  la ip y puerto específico del servidor:

# Listen: Allows you to bind Apache to specific IP addresses and/or
# ports, instead of the default. See also the <VirtualHost>
# directive.
#
# Change this to Listen on specific IP addresses as shown below to
# prevent Apache from glomming onto all bound IP addresses.
#
#Listen 12.34.56.78:80

Listen 127.0.0.1:80
Listen 172.16.161.129:80

Un saludo.

Diciembre 19, 2008

CodeIgniter + jquery: uso de File Uploading Class sin refresco de pantalla

En la documentación de CodeIgniter, disponemos de un breve pero útil tutorial para el buen uso de File Uploading class, que nos permite procesar input files, y obtener las propiedades del archivo en cuestión para el uso que estimemos oportuno.

El problema se presenta cuando estamos procesando el formulario en el que se encuentra el hipotético input file mediante de ajax. En ese punto hay diversas alternativas. Lo habitual, imagino, es usar uno de esos cómodos y efectivos plugins de jquery (el framework de js que uso para el proyecto). Sin embargo, me encontré con problemas graves a la hora de integrar la lógica del plugin con la estructura MVC de CodeIgniter.

Eso, y que soy un tipo perezoso poco dado a abrir nuevos caminos a la humanidad, me ha llevado a buscar el camino más directo y rápido. La idea es la siguiente:

  1. Presentamos un formulario, y en vez de incluir el input file, mostramos un vínculo “Upload File”.
  2. Cuando el usuario pincha en el vínculo, mostramos pop-up (mi opción personal) desde el que subiremos el archivo.
  3. Una vez subido el archivo, mostramos confirmación y pasamos toda la información del archivo a la pantalla inicial, donde podemos mostrar la previsualización de la imagen (si es una imagen) y disponernos a guardar la información precisa cuando enviemos el formulario a procesar.

A continuación os paso el código, que sigue en todo lo posible el tutorial original de File Uploading Class de Codeigniter, con las modificaciones necesarias.

Primero creamos el controlador upload.php, que es muy parecido al del tutorial original.

<?php

class Upload extends Controller {

function Upload()
{
parent::Controller();
$this->load->helper(array(’form’, ‘url’));
}

function index()
{
$this->load->view(’index_form’);
}

function popup_file()
{
$this->load->view(’upload_form’, array(’error’ => ‘ ‘ ));
}

function do_upload()
{
$config['upload_path'] = ‘./uploads/’;
$config['allowed_types'] = ‘gif|jpg|png’;
$config['max_size'] = ‘100′;
$config['max_width'] = ‘1024′;
$config['max_height'] = ‘768′;

$this->load->library(’upload’, $config);

if ( ! $this->upload->do_upload())
{
$error = array(’error’ => $this->upload->display_errors());
$this->load->view(’upload_form’, $error);
}
else
{
$data = array(’upload_data’ => $this->upload->data());
$this->load->view(’upload_success’, $data);
}
}
}
?>

A continuación creamos las 3 vistas que carga el controlador.

Primero, index_form.php, la vista inicial donde queremos cargar la imagen sin que haya refresco de pantalla, junto con las propiedades que más tarde guardaremos en una base de datos, o utilizaremos como creamos conveniente.

<head>
<title>Upload Form</title>
</head>
<body>
<?php
$atts = array(
‘width’ => ‘400′,
‘height’ => ‘500′,
’scrollbars’ => ‘yes’,
’status’ => ‘yes’,
‘resizable’ => ‘yes’,
’screenx’ => ‘0′,
’screeny’ => ‘0′
);

echo anchor_popup(’upload/popup_file’, ‘Upload file’, $atts);
?>
<div id=”file_info”></div>
</body>
</html>

Ahora, creamos upload_form.php, el formulario donde se realiza el envío del archivo, y que se cargará dentro del pop-up:

<html>
<head>
<title>Upload Form</title>
<script type=”text/javascript” src=”<?php echo base_url();?>js/jquery/jquery.js”></script>
<script language=”javascript” type=”text/javascript”>
$(document).ready(function(){
$(”#btn_send”).click( function (e) {
e.preventDefault();
$(”#frm_image”).submit();
});
});
</script>
</head>
<body>
<?php echo $error;?>
<form
action=”<?php echo site_url(’upload/do_upload’); ?>”
enctype=”multipart/form-data”
method=”post”
id=”frm_image” >
<input type=”file” name=”userfile” id=”userfile” size=”20″ />
<a href=”" id=”btn_send”>Enviar</a>
</form>
</body>
</html>

Finalmente, la vista upload_success.php, que en el tutorial muestra las propiedades del archivo procesado, nos va a servir para reenvíar mediante jquery todas esas interesantes propiedades a la ventana original:

<html>
<head>
<title>Upload Form</title>
<script type=”text/javascript” src=”<?php echo base_url();?>js/jquery/jquery.js”></script>
<script language=”javascript” type=”text/javascript”>
$(document).ready(function(){
$(”#volver”).click(function(e){
e.preventDefault();
var op = window.opener.document;
$(”#file_info”,op).append($(”#file_info”).html());
window.close();
});
});
</script>
</head>
<body>
<h3>Your file was successfully uploaded!</h3>
<div id=”file_info”>
<ul>
<?php foreach($upload_data as $item => $value):?>
<li><?php echo $item;?>: <?php echo $value;?></li>
<?php endforeach; ?>
</ul>
<img src=”<?php echo base_url() . ‘uploads/’ . $upload_data['file_name']; ?>” border=”0″ />
</div>
<a href=”" id=”volver”>Volver</a>
</body>
</html>

Bueno, cómo veis es muy sencillo y básico. Infinitamente mejorable. Pero cuando sientes el aliento del cliente en el cogote, lo “perfecto” puede ser enemigo de lo “bueno”.

Felices fiestas.

Noviembre 14, 2008

Primer mandamiento del Programador

No tengo la más remota idea de quién es Martin Goldin, pero este señor soltó una frase que creo deberíamos escribir 100 veces en la pizarra antes de comenzar a picar código como si nos fueran a quitar el teclado …

“Programa como si el tío que va a mantener tu código fuera un psicópata violento que sabe dónde vives.”

En el idioma original, “Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.”

Amén.

Y de paso incluyo algunas perlas sobre este maravilloso oficio…

“Never trust a computer you can’t throw out a window.”
(Steve Wozniak)

“The trouble with programmers is that you can never tell what a programmer is doing until it’s too late.”
(Seymour Cray)

“Saying that Java is nice because it works on all OSes is like saying that anal sex is nice because it works on all genders.”
(Alanna)

“If Java had true garbage collection, most programs would delete themselves upon execution.”
(Robert Sewell)

“If debugging is the process of removing bugs, then programming must be the process of putting them in.”
(Edsger W. Dijkstra)

“Programming is like sex: one mistake and you’re providing support for a lifetime.”
(Michael Sinz)

“A computer lets you make more mistakes faster than any invention in human history–with the possible exceptions of handguns and tequila.”
(Mitch Radcliffe)

Noviembre 14, 2008

Ampliar tamaño de disco de máquina VMware

En este caso, tenemos una máquina virtual de VMware de 5Gb, que se nos ha quedado pequeña.

Para realizar la ampliación, tenemos que usar la utilidad vmware-vdiskmanager que viene con la versión Workstation o superior de VmWare.

En este ejemplo vamos a fijar el tamaño final de la máquina virtual (guardad en un disco externo) en 10Gb.

Para ello, abrimos la línea de comandos y vamos al directorio donde tenemos la utilidad, normalmente “C:\Archivos de programa\VMware\VMware Workstation\”

Y ejecutamos lo siguiente (incluyo el nombre de mi máquina como ejemplo):

vmware-vdiskmanager.exe -x 10Gb “[ruta donde guardas máquinas]\Windows XP Professional-cl1.vmdk”

Como ves, si la ruta contiene espacios es imprescindible poner comillas. También es importante poner el tamaño final que queremos, no el incremento.

Por último, tenemos que iniciar la máquina y utilizar una herramienta para administrar particiones para que Windows reconozca el nuevo espacio de la partición.

Nosotros hemos utilizado EASEUS (gratis para Windows XP y Vista y bastante fácil de utilizar).

Este post se lo debo a Pedro, amigo y compañero de curro en One Way Clear. Gracias Peter!

Octubre 31, 2008

Problema con caracteres especiales en Netbeans IDE en Ubuntu

Al instalar el Netbeans IDE 6.5 Beta, me doy cuenta de que no puedo escribir carácteres especiales como []{}@#\, etc, ni tampoco acentos. Por lo que parece es un problema de teclado que afecta a las aplicaciones Java.

Después de consultar algunos foros, ésta es la solución que funciona para mí:

Abrir archivo /etc/scim/global:

sudo gedit /etc/scim/global

En mi caso, edito donde pone:

/SupportedUnicodeLocales = en_US.UTF-8

que queda así:

/SupportedUnicodeLocales = es_ES.UTF-8,en_US.UTF-8

Octubre 29, 2008

Deshabilitar el Touchpad en Ubuntu

Odio los Touchpads… sobre todo si son tan sensibles como el de mi portátil: basta un leve amago de acercamiento para que te mande el cursor a otro extremo de la pantalla. Así que decidí librarme de este incordio. Después de mirar diversas fuentes, vi que era bastante fácil:

Editamos el xorg.conf:

sudo gedit /etc/X11/xorg.conf

Buscamos la sección donde pone:

Section “InputDevice”

Identifier “Synaptics Touchpad”

Ojo, hay varias secciones “InputDevice”, edita la correcta.

Añade al final:

Option       “SHMConfig”        “on”

Ahora ya podemos ir al Terminal para habilitar o deshabilitar el Touchpad con los comandos:

synclient touchpadoff=1 (para deshabilitar)

synclient touchpadoff=0 (para habilitar)

Si al ejecutar este comando nos da un error:

Can’t access shared memory area. SHMConfig disabled?

Seguramente es porque editamos el xorg.conf incorrectamente, o nos equivocamos de Section (a mí me paso por despistado).

Si el error persiste, prueba a reiniciar X (Ctrl+Alt+Backspace) y vuelve a intentarlo.

De cualquier forma, para que el cambio tenga efecto al final de todo el proceso, tendrás que reiniciar X.

Esta deshabilitación dura lo que dura la sesión. Si queremos que el Touchpad se deshabilite siempre que iniciamos sesión, sólo hay que dar un pasito más:

Vamos a Sistema > Preferencias > Sesiones.

En la pestaña “Programas de inicio” hacemos click en el botón “Añadir”.
En el formulario, le damos un nombre cualquiera, mejor si es identificativo, y en Orden escribimos el famoso:

synclient touchpadoff=1

Eso es todo.

De bien nacidos es ser agradecidos:
http://www.linuxine.com/2008/06/how-to-disable-touchpad-in-ubuntu.html
http://ubuntu.wordpress.com/2006/09/20/disable-touchpad-temporarily-when-typing/

Octubre 29, 2008

¿Es Titanic realmente una película sobre el hundimiento de un barco que choca contra un iceberg?

Un extracto del ensayo de Slavoj Zizek en “Arte, ideología y capitalismo”:

¿Es Titanic realmente una película sobre el hundimiento de un barco que choca contra un iceberg? Es preciso tener en cuenta que la catástrofe se produce justo en el momento en que los dos jovenes amantes regresan a la cubierta del barco inmediatamente después de consumar sexualmente su relación amorosa. Pero eso no es todo.

De otro modo, la catástrofe hubiera sido el castigo del Destino por la doble transgresión que supone el acto sexual ilegítimo y la contravención de las divisiones de clase.Lo realmente crucial es que, una vez en cubierta, Kate le dice apasionadamente a su amante que, cuando a la mañana siguiente el barco llegue a Nueva York, se marchará con él. Prefiere vivir en la pobreza junto a su auténtico amor a una vida de falsedad y corrupción entre los de su clase social. Precisamente en ese momento el barco choca el iceberg a fin de prevenir lo que sin ningún género de dudas hubiera sido la auténtica catástrofe, es decir, la vida de la pareja en Nueva York: cabe suponer sin sombra de duda que las miserias de la vida cotidiana no tardarían en acabar con su romance. El siniestro se produce con el objeto de salvar su amor, generando la ilusión de que, si no hubiera tenido lugar, habrían vivido “felices por siempre”.

Pero ni siquiera esto es todo. Los momentos finales, en los que se ve cómo Di Caprio muere de hipotermia en el agua gélida mientras Winslet flota a salvo sobre un trozo de madera, nos proporcionan una clave adicional. Consciente de que le está perdiendo, ella grita:”Nunca te dejaré marchar!”, y al tiempo que lo dice, ella LE DEJA MARCHAR, incluso llega a empujarle con sus propias manos. ¿Por qué? Porque él ya ha cumplido su cometido.

Tras el relato de amor, Titanic oculta otra historia bien distinta acerca de una niña mimada de clase alta que vive una crisis de identidad: está confusa, no sabe qué hacer con su vida.. Di Caprio no es tanto su pareja amorosa cuanto una especie de “mediador evanescente” cuya función es restaurar su identidad y el sentido de su vida, su imagen personal (bastante literalmente, por cierto: él dibuja su imagen). Una vez que ha terminado su trabajo debe esfumarse.

Octubre 10, 2008

Tarta de hojaldre a prueba de manazas

  • láminas de hojaldre
  • manzana o plátanos
  • azúcar morena
  • mantequilla

Necesitamos 1/2 metro de encimera limpia y despejada. Esparcimos algo de harina encima de la encimera para que no se nos pegue la lámina de hojadre. Depositamos con cuidado el hojaldre y antes de que le de tiempo a reaccionar lo aplastamos con un rodillo de madera. Si no disponemos de rodillo podemos utilizar una botella de cristal (preferiblemete vacía, o empezarán los problemas).

Ahora seleccionamos una fuente o bandeja (o algo que sirva como tal). Debería tener 2 cms de profundida aproximadamente. La embadurnamos con mantequilla; se puede utilizar una brocha (pero no utilices esa que tienes en la caja de herramientas). Ahora forramos la fuente con la lámina de hojadre. La masa de hojaldre debe sobresalir por todo el perímetro de la fuente (¿cómo? yo acabo haciendo empalmes por todas partes, pero al final lo consigo…)

Ahora troceamos el plátano o la manzana. La manera de trocearlos queda un poco a gusto de cada uno. En mi caso, suelo hacer trocitos de un dedo de grosor. Si se hacen trozos demasiado pequeñitos, se acabará convirtiendo en un puré, y no se trata de eso, la fruta debe ser reconocible.

Por cierto, en el caso de los platanos debieran ser más bien maduritos. Y en cuanto a las manzanas, elije algo que hubiera podido comerse “La Bella Durmiente” sin perder los incisivos.

A continuación, esparcimos 3 cucharadas de azúcar morena sobre la base de hojaldre. Y ahora vamos colocando los trocitos de fruta encima de la base. Tienen que ocupar toda la base pero sin aprietos; no tiene porque ser el Metro en hora punta, pero que tampoco haya sitio para sentarse.

Hecho esto, esparcimos otras 10 cucharadas de azúcar morena a modo de tapaporos entre la fruta. No seas rácano: es un postre dulce.

Con un cuchillo cogemos “garbancillos” de mantequilla (la expresión es de mi madre) y los echamos por encima de la fruta y el azúcar. Con 10 trocitos es suficiente. Lo coronamos todo con una ramita de canela.

Ahora necesitamos tapar todo esto, así que aplastamos con el rodillo otra lámina de hojaldre. Con dicha lámina, tapamos la fuente, y de nuevo, tiene que sobrarnos hojadre por todo el perímetro.

Finalmente necesitamos sellar el invento para que no se escape el contenido cuando lo calentemos; lo que hacemos es ir cogiendo la masa que sobra alrededor de la fuente, tanto de la lámina base como de la superior, y la vamos enrollando sobre sí misma usando los dedos.

Cuando este todo bien cerradito, embadurnamos con clara de huevo (o mantequilla) la “tapa” de la tarta y la metemos en el horno a 150 grados (el horno debería estar precalentado).

Consejo: conviene poner papel albal en la la base del horno, ya que a veces rezuma algo de azúcar, chorrea y luego se limpia fatal.

Octubre 6, 2008

Errores al actualizar repositorios de Ubuntu

De vez en cuando al actualizar repositorios mediante apt-get update se pueden producir errores del tipo:

No pude conectarme a es.archive.ubuntu.com:80 (150.214.5.135). – connect (111 Conexión rechazada)

Imposible obtener http://es.archive.ubuntu.com/ubuntu/dists/hardy/main/i18n/Translation-es.bz2 No pude conectarme a es.archive.ubuntu.com:80 (150.214.5.135). – connect (111 Conexión rechazada)

Una manera rápida de solucionar estos problemas es buscar los repositorios más apropiados en ese momento:

  1. Sistema > Administracion > Origenes del Software.
  2. En la lista desplegarble “Descargar Desde” seleccionar “Otro…”.
  3. Pulsar en “Seleccionar el mejor servidor.
  4. Una vez localizado el mejor servidor, pulsar en “Seleccionar servidor”.