Posts etiquetados ‘Servidor’


You can read the English version of this post in http://phpsblog.agustinvillalba.com/objects-and-references-in-memory-in-php/

Hoy vamos a hablar sobre cómo PHP crea los objetos en memoria cuando realizamos una instrucción del tipo $a = new Foo(); y sobre cómo son gestionadas las referencias en memoria, dado que este es un tema que puede generar debate y diferencia de opiniones. Para ello hablaremos de lo qué NO son las referencias en PHP. Por último, veremos cómo funciona el recolector de basura (o garbage collector) en PHP.

Objetos y referencias en PHP

Una afirmación que está muy extendida en los libros de PHP, y en la red en general, es que en PHP los objetos, por defecto, se pasan por referencia. También hay quienes dicen que los objetos en PHP se asignan por copia. Estas afirmaciones no son completamente ciertas, y para comprobarlo primero hemos de analizar qué son (y qué NO son) las referencias en PHP.

Qué NO son las referencias en PHP

Creo que más importante que saber qué son las referencias en PHP, hemos de aclarar qué NO son las referencias en PHP. En PHP las referencias no son punteros al estilo C, no podemos realizar operaciones aritméticas con las referencias como se puede hacer en C. ¿Por qué? Porque en PHP las referencias no son en realidad direcciones de memoria como en C, no son números que indican una posición de memoria. Pero entonces… ¿qué son en realidad las referencias?

Qué son las referencias en PHP

En PHP, las referencias son «alias» que permiten que 2 variables distintas puedan escribir sobre un mismo valor. O visto de otra manera, son un mecanismo que nos permiten acceder un mismo valor desde nombre de variables distintos y que se comporten como si fueran la misma variable. Hay que tener en cuenta que, en PHP, el nombre de la variable y el contenido de esa variable son 2 cosas totalmente distintas que se enlazan en lo que se llama la tabla de símbolos. De forma que cuando creamos una referencia, simplemente se está añadiendo un alias de dicha variable en la tabla de símbolos de PHP. Veámoslo con un ejemplo, supongamos que tenemos el siguiente código:

$a = new Foo();

Cuando se ejecuta la instrucción anterior, realmente lo que está sucediendo es que se crea una variable «a» en memoria, se crea un objeto de tipo Foo en memoria y se añade una entrada en la tabla de símbolos de PHP en la que se indica que la variable $a «referencia» (o se relaciona, o «apunta», o como se quiera llamar) al objeto Foo, pero NO es un puntero a dicho objeto. Si a continuación ejecutamos la instrucción:

$b = $a;

Lo que ocurre no es que se $b se convierta en una referencia de $a, tampoco se puede decir que $b sea una copia de $a. Lo que realmente ha sucedido es que se ha creado una nueva variable «b» en memoria y luego se ha añadido una nueva entrada en la tabla de símbolos indicando que la variable $b, también «referencia» al mismo objeto Foo que $a. Si a continuación ejecutamos la instrucción:

$c = &$a;

Lo que ocurre es que en memoria se habrá creado una tercera variable «c» pero NO se añade una nueva entrada en la tabla de símbolos para «c», sino que en la tabla de símbolos se indica que «c» es un alias de «a», por lo tanto se comportará de forma idéntica que esta, pero no es que «c» sea un puntero a «a» (lo que en C se conoce como punteros a punteros).
Veamos un ejemplos más completo:

<?php

class myClass {
    public $var;
		
    function __construct() {
	$this->var = 1;
    }

    function inc() { return ++$this->var; }
}

$a = new myClass(); // $a "referencia" a un objeto Foo
$b = $a; //b también referencia al mismo objeto Foo que a
//($a) == ($b) == <id> del objeto Foo, pero a y b son entradas distintas en la tabla de símbolos

echo "\$a = ";var_dump($a);
echo "\$b = ";var_dump($b);

$c = &$a; //$c es un alias de $a
//($a, $c) == <id> del objeto Foo, c es un alias de a en la tabla de símbolos
echo "\$c = ";var_dump($c);

$a = NULL;
//Se elimina la entrada en la tabla de símbolos donde se relacionaba a "$a" con el objeto Foo
//Al eliminarse esta entrada, $c también deja de estar relacionado con Foo
//A todos los efectos, Foo sigue existiendo en memoria, y sigue estando relacionado con $b
echo "\$a = ";var_dump($a);
echo "\$b = ";var_dump($b);
echo "\$c = ";var_dump($c);
echo "\$b->var: ".$b->inc();
echo "\$b->var: ".$b->inc();

$b = NULL;
//Se elimina la entrada en la tabla de símbolos donde se relacionaba a "$b" con el objeto Foo
//Ya no hay más entradas en la tabla de símbolos que se relacionen con Foo,
//Por lo que Foo ha dejado de estar referenciado y puede ser eliminado por el garbage collector

echo "\$b = ";var_dump($b);

Las salidas que produce la ejecución del script anterior son:

$a = object(myClass)#1 (1) { ["var"]=> int(1) } 
$b = object(myClass)#1 (1) { ["var"]=> int(1) } 

$c = object(myClass)#1 (1) { ["var"]=> int(1) } 
$a = NULL 
$b = object(myClass)#1 (1) { ["var"]=> int(1) } 
$c = NULL 
$b->var: 2
$b->var: 3

$b = NULL

Garbage collector en PHP

Por último, veamos cómo funciona el garbage collector (o recolector de basura) en PHP. Un objeto o una variable en PHP podrá ser eliminada de memoria por el garbage collector cuando no exista ninguna referencia a dicho objeto en la tabla de símbolos. Es decir, PHP mantiene un contador de referencias a un objeto desde el momento en que éste es creado, de forma que durante la ejecución del script PHP va incrementando y decrementando dicho contador de referencias en función de las variables que le van «apuntando». Una vez ese contador de referencias llega a 0 (es decir, nadie está relacionado con ese objeto y por lo tanto, no se está utilizando dicho objeto), PHP marca ese objeto como basura o eliminable, de forma que en la siguiente pasada del garbage collector, éste eliminará dicho objeto de memoria y esa posición de memoria será utilizable por PHP nuevamente.

De esta forma esperamos haber aclarado un poco más cómo gestiona PHP los objetos y variables en memoria y cómo se «seleccionan» los objetos que han de ser eliminados por el recolector de basura en PHP.

You can read the English version of this post in http://phpsblog.agustinvillalba.com/objects-and-references-in-memory-in-php/


Creo que con el título de este artículo poca introducción es necesaria. Hoy no voy a hablar de código ni de variables, pero sí de algo que tiene que ver con la web, y es el proveedor de hosting 1and1 (España) y la pésima experiencia que tuve con su servicio de atención al cliente la primera vez que lo necesité desde que soy cliente suyo.

Hace ya más de un mes, exactamente el día 27 de Octubre de 2011 recibí un correo electrónico del departamento de soporte de 1and1.es que decía así:

Estimado/a Agustín Villalba Casás:

Con este correo electrónico deseamos informarle de antemano de un cambio
en el servidor web de 1&1:

En el marco de unos trabajos de mantenimiento del sistema, durante la
semana
del 31 de octubre al 4 de noviembre se llevará su paquete de hospedaje 1&1
a un entorno operativo actualizado y así podremos seguir ofreciéndole un
entorno
óptimo y altamente seguro.

No se requieren trabajos preparatorios o de ajuste por su parte.
La conversión se lleva a cabo de forma totalmente automática. Sin embargo,
su paquete de hospedaje no estará disponible durante 5 o 10 minutos entre
las
8:45 y las 18:45. Una vez terminada la conversión, podrá disponer de todas
las aplicaciones tal y como está acostumbrado.

Lamentamos que por motivos técnicos no podamos indicar con exactitud la
hora de conversión de su paquete de hospedaje.

¿Cuáles son las mejoras?
=============================
Además de un mejor rendimiento y de mayor seguridad, la conversión a un
entorno operativo Linux (basado en Debian Squeeze/6.0) especialmente
adaptado
a 1& 1 y a sus clientes incluye una actualización de los componentes
siguientes:

Apache 2.2

http://apache.org/

Tenga en cuenta que con la conversión pueden darse algunos cambios en la
configuración del tiempo de ejecución. Así, por ejemplo, con la instrucción
"IndexOptions FancyIndex" se accede ahora a la función que anteriormente
ponía
a disposición el comando "FancyIndex On", entretanto nulo.

http://httpd.apache.org/docs/2.0/upgrading.html

Asimismo, si usa scripts o software muy antiguos, queremos indicarle que
determinadas variables internas, como, por ejemplo, "REMOTE_USER" solo
estarán
disponibles tras un redireccionamiento del Apache
como 'REDIRECT_REMOTE_USER'.

Python 2.6
http://www.python.org
http://docs.python.org/release/2.6.7/whatsnew/2.6.html

Perl 5.10.1
http://perldoc.perl.org/
http://perldoc.perl.org/http://perldoc.perl.org/5.10.1/index.html

Para estas actualizaciones no es necesario que realice acciones.
Estarán automáticamente disponibles tras la conversión. 

A pesar de todo, si tras la conversión algo no funcionara de la forma
acostumbrada
o si tuviera más preguntas, no dude en ponerse en contacto con nuestro
servicio de
soporte.

Como se desprende del correo, la actualización únicamente iba a ser relativa a la versión del servidor web y algunos aspectos de seguridad. Como ellos mismos mencionan, «No se requieren trabajos preparatorios por su parte» y «…si tras la conversión algo no funcionara de la forma acostumbrada o si tuviera más preguntas, no dude en ponerse en con nuestro servicio de soporte.» Con esto en mente uno piensa que su sitio web no tiene porqué dejar de funcionar tras la actualización, dado que no mencionan en ningún momento que se vaya a modificar la configuración del servidor PHP ni ninguno de sus módulos disponibles antes de la actualización, aún así, inspiran cierta tranquilidad invitando a pensar que si algo no funcionara tras la actualización todo se arreglaría con llamarlos, comentarles el problema y todo volvería a la normalidad.

Pues cuál fue mi sorpresa cuando la semana pasada, el día 28 de noviembre de 2011, estaba haciendo algunas pruebas en mi sitio web alojado en sus servidores y descubro que mi servicio de «Contacto» no envía correos electrónicos. Me extrañó mucho, dado que en mi servidor de desarrollo el código funcionaba a la perfección pero en el de producción (1and1) no. Para ello utilizo la librería PHPMailer, por lo que estuve durante 2 horas examinando el código de la librería por cualquier cosa que se haya podido corromper en la subida de los archivos, pero no encontraba nada extraño. Hasta que llegado a un punto recordé la actualización de la que me habían advertido hacía más de un mes. Comencé a comparar línea por línea la configuración de mi servidor PHP de desarrollo y la configuración del servidor PHP de 1and1, hasta que descubrí que el problema era que en la configuración del servidor PHP de 1and1 había desaparecido el módulo de Sockets. Estupendo, ya tenía el motivo, tan sólo tenía que llamar a 1and1, pedirles que me activaran este módulo y todo volvería a la normalidad como me habían dado a entender en su e-mail.

Llamo al servicio de atención al cliente (un número 902… nada barato) y me atiende un hombre bastante agradable inicialmente. Antes de hablar con este hombre, una contestador me advirtió de que la conversación iba a ser grabada, ahora tras la experiencia: ¡menos mal que la grabaron!. Al susodicho operador, le comento mi problema y me pide que espere para que él pueda comprobar la configuración de mi servidor PHP. Tras 3 minutos de espera, vuelve y me dice que efectivamente el módulo de Sockets no está instalado (algo que ya le había dicho yo al inicio de mi llamada). Le pido si por favor me lo pueden activar, que una parte de mi sitio depende de ese módulo para su correcto funcionamiento y me dice que «tendré que revisar mi código y 1and1 no da soporte al código de aplicaciones realizadas por terceros» (???). Le repito que no necesito que me de soporte a mi código PHP, además de que ese mismo código tal cual está funcionaba antes de la actualización, y en su correo mencionaban que no serían necesarios cambios por mi parte, y tras la actualización ese código sin que nadie lo manipulara dejó de funcionar. A esto, el personaje al teléfono, me responde que la actualización «no afectaba a los módulos de PHP, que era únicamente de seguridad de Apache para dar un mejor servicio a los usuarios y bla bla bla…». Si no afectaba a los módulos, ¿por qué desapareció el módulo de Sockets de PHP?

Tras 10 minutos intentando que el buen hombre entendiera que no necesito soporte a mi código de PHP y que si la actualización no afectaba a los módulos de PHP por qué desapareció el módulo de sockets, me da una nueva excusa al problema diciéndome que «la nueva versión de hostings compartidos del servidor no habilita el módulo de Sockets» y dado que yo tengo contratado hosting compartido, ese módulo no me lo pueden activar. ¿Versión de hostings compartidos del servidor? Servidor PHP hay uno y cada uno lo configura como necesita, o ¿desde cuándo PHP saca versiones de hostings compartidos de su servidor? Pues tras esta excusa, intento pedirle si hay alguna posibilidad de que se active el módulo de Sockets mediante un php.ini para mí o (a la desesperada) mediante un .htaccess en mi sitio. A todo ello responde con un rotundo «NO» sin pararse ni medio segundo a meditar cada una de las opciones.

En vista de que ya llevaba 15 minutos al teléfono y el humanoide al otro lado no dejaba de repetir cíclicamente las 3 excusas que se tenía aprendidas: «No damos soporte al código de terceros», «La actualización era de seguridad» y «la nueva versión de hostings compartidos no habilita el módulo de Sockets», le pedí que me pasara con un superior para aclarar el asunto, y su respuesta no fue otra que «No le voy a pasar con un superior, yo soy el agente responsable de esta llamada». ¡Increíble! No sólo no me había dado solución a mi problema sino que además me negaba el derecho de hablar con un superior suyo. Ante mi indignación, y tras 2 minutos insistiéndole para que me dejara hablar con un superior, me dice con altanería «lo siento señor, pero tengo liberar la línea» y me colgó el teléfono. Sencillamente espectacular pensé, un servicio de atención al cliente ¡que le cuelga el teléfono al cliente!

Tras dejar pasar un rato para calmarme, volví a llamar esperando hablar con otro operador que sí tuviera ganas de solucionar mi problema. La conversación discurrió en términos parecidos a la anterior, pero esta vez el operador, además de no colgarme el teléfono, se comprometió a comunicar mi caso al departamento de sistemas y ver qué se podía hacer.

En un intento desesperado de saber si existía algún operador capaz de ayudarme, volví a llamar por tercera y última vez. Tras comentarle mi problema y él comprobar que no estaba habilitado el módulo de sockets, me dijo que «iba a ser imposible solucionarlo». Pasamos de un «ver que se puede hacer…» a un «imposible», no pintaba bien la cosa. Le comenté que ese módulo era muy importante para mi sitio web y me dijo que no podía hacer nada. Le comenté la impotencia que me daba el saber que 1and1 me retiraba de forma unilateral y sin previo aviso un módulo que era necesario para el correcto funcionamiento de mi web y su respuesta fue… silencio. Le dije que «con esto me están empujando a abandonar 1and1, retirar de allí mi web, e irme con otro proveedor de hosting que sí me ofrezca el módulo de Sockets», y su respuesta fue literlamente «usted puede emprender las acciones que considere oportunas…», ¡vaya forma de cuidar a su clientela que tiene 1and1!

Al día siguiente pedí a 2 amigos que tienen hosting con CDMon y HostMonster que me permitieran ver sus configuraciones del servidor PHP, y cuál fue mi sorpresa cuando vi que esos hostings sí tienen módulos de Sockets, con lo cual, se confirma lo que ya sabíamos, la excusa de «la nueva versión del servidor de hostings compartidos no habilita el módulo de Sockets» era una burda y penosa mentira del operador que me atendió.

En definitiva, no activaron el módulo de sockets y yo SÍ tuve que modificar mi código para que mi web funcionara (a pesar de que ellos mintieran diciendo que no sería necesario) mientras hago la migración de mi web a otro proveedor de hosting que sí tiene activados los módulos de Sockets.

Mi humilde consejo: No contrates los servicios de 1and1. Todos estos dolores de cabeza que he tenido yo no tienes porqué pasarlos tú. No permitamos que se nos trate como si estuviéramos molestando a los señores de atención al cliente cuando, muy de vez en cuando, requerimos su ayuda. Me gustaría pedirles un favor. Todos aquellos que tengan Twitter, Facebook o cualquier red social… por favor, difundan la noticia y aporten su granito por llegar al mayor número de gente posible. Nos merecemos servicios de soporte de calidad, que eso también nos los cobran. En Twitter podríamos copiar y retwittear el mensaje «@1and1_ES por un servicio de #atencionalcliente de calidad http://wp.me/pIXJS-59 @agustinvillalb Por favor, retwittea!» Muchas gracias a todos!


You can read the English version of this post in http://phpsblog.agustinvillalba.com/upload-progress-bar-in-codeigniter-without-flash/

Hoy vamos a ver cómo podemos crearnos una barra de progreso de subida de archivos en CodeIgniter sin la necesidad de recurrir a librerías o plug-ins hechos en Flash (del tipo SWFUpload, etc) que escapan a nuestro control, dado que habitualmente estas librerías nos ofrecen los archivos .swf ya compilados, por lo que nos es imposible modificar nada en ellos, en el caso de que tengamos conocimientos de programación en ActionScript 2 o 3.

Antes que nada hemos de decir que crear una barra de progreso de subida de archivos en PHP no es tan sencillo como pudiera parecer. El primer problema es que las versiones de PHP anteriores a la 5.2 no ofrecen las herramientas necesarias para poder ofrecer información sobre cómo la subida del archivo en cada momento. El segundo problema es que AJAX, por sí solo, no nos permite consultar el estado de la subida del archivo, dado que, por razones de seguridad obvias, JavaScript no tiene acceso a los archivos del sistema operativo del cliente, por lo que necesitaremos un «truco» utilizando un iframe.

(más…)


You can read the English version of this post in http://phpsblog.agustinvillalba.com/automatic-configuration-of-url-in-codeigniter/

En este mini-post voy a explicar cómo configurar nuestro CodeIgniter para que funcione en cualquier servidor sin tener que estar modificando los parámetros de configuración de la «base_url». De esta forma, podemos trasladar nuestra versión de desarrollo a nuestro servidor de producción sin preocuparnos de tener que cambiar nada en la configuración. Para esto lo único que tenemos que hacer es modificar el siguiente código en nuestro archivo system/application/config/config.php:

$config['base_url'] = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == "on") ? "https" : "http");
$config['base_url'] .= "://".$_SERVER['HTTP_HOST'];
if (!isset($_SERVER['ORIG_SCRIPT_NAME']))
{
  $config['base_url'] .= str_replace(basename($_SERVER['SCRIPT_NAME']),"",$_SERVER['SCRIPT_NAME']);
}
else
{
  $config['base_url'] .= str_replace(basename($_SERVER['ORIG_SCRIPT_NAME']),"",$_SERVER['ORIG_SCRIPT_NAME']);
}

Con este sencillo código ya podemos trasladar nuestra apliación sin necesidad de preocuparnos de configurar correctamente su URL.

You can read the English version of this post in http://phpsblog.agustinvillalba.com/automatic-configuration-of-url-in-codeigniter/