Archivo

Archivo para la categoría ‘PHP’

Identificar si estamos en el servidor local o no

Lunes, 25 de Enero de 2010 admin Sin comentarios

A veces es interesante saber en qué servidor estamos, si en nuestro servidor local para hacer pruebas, o en el remoto (y será la web definitiva); puede que porque las claves de mi servidor MySQL local son diferentes, o porque en local activamos automáticamente el modo de depuración, o símplemente porque en nuestro servidor local tenemos todos nuestros proyectos como http://localhost/proyecto1/ y en el servidor se ejecutarán como http://www.proyecto1.com/.

Para ello nos vale esta línea que podemos incluir en nuestra biblioteca de funciones personal en PHP:

1
$serv_local = (file_exists($_SERVER['DOCUMENT_ROOT']."/serv_local"));

Ahora en nuestro servidor local (valga la redundancia en todo el post) hacemos un touch en nuestro DOCUMENT_ROOT (por ejemplo /home/www/public_http/):

1
2
$ cd /home/www/public_http
$ touch serv_local

Con esto siempre que ejecutemos nuestros scripts buscaremos el fichero serv_local, si se encuentra, estamos seguros de que estamos en nuestro ordenador, si no, estamos en el servidor remoto.

Categories: PHP Tags: , ,

Caché+Compresión+Palabras clave en ficheros CSS y JS

Viernes, 22 de Enero de 2010 admin Sin comentarios

Cuando nos aventuramos en un proyecto web con más o menos visitas, queremos que sea lo más rápido para el usuario y para ello enviar la menor cantidad de información (si nuestro hosting nos cobra además por transferencia también ganamos por esto), para ello podemos comprimir la información (y ya lo soportan la mayoría de los navegadores).
Aunque tenemos que tener en cuenta que si comprimimos información (la compresión es un proceso algo pesado), estamos gastando recursos de CPU que, si lo pensamos, estar comprimiendo la misma información a cada petición que nos hagan de un fichero Javascript es tontería; por tanto, una vez que lo comprimamos, lo almacenamos en disco, que este tipo de información no ocupa tanto.
Por otra parte, si eres de los que realizan una plantilla más o menos completa y la publica con pequeñas modificaciones en diferentes webs, o incluso estar preparados para que un cliente nos cambie la gama de colores y no echarnos las manos a la cabeza; o por ejemplo cuando tenemos que tener en cuenta el mismo color tanto en el código CSS como en el Javascript, podemos escribir ciertas palabras clave dentro del fichero CSS y Javascript que nuestro script PHP traducirá antes de enviar la información al usuario final.

Para ello, y para poco más es el siguiente script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
<?
/* tcjs.php versión 0.05 Copyright 2010 Gaspar Fernández*/

/* Inclusión de keywords y compresión de archivos JS y CSS */

/* El código fuente se entrega tal cual, sin garantía para ser */
/* estudiado y utilizado en cualquier entorno libre y no libre. */
/* Eso si, agradecería que me comunicárais si lo usáis en un proyecto */
/* mandando un mail a blakeyed@totaki.com; sólo para saber que esto  */
/* se está usando en algún lugar del mundo :) */

/* Configuración del script */

/* $basepath normalmente es la ruta donde se encuentra el script. Es la ruta base
absoluta a partir de la cual se encuentran todos los archivos. Esta ruta será padre
de la ruta donde se encuentre el fichero CSS o JS que llamaremos. */

$basepath = '/home/gaspy/proyectos/www/poesiabinaria/tests/';
/* $httppath es la URL base de nuestra web o sección, normalmente será la dirección con la que
abriremos el directorio web correspondiente a $basepath. */

$httppath = 'http://localhost/poesiabinaria/tests/';
/* $cachedir es el directorio donde se encontrarán los cachés de los ficheros JS y CSS */
$cachedir = $basepath.'var/gzcache/';
/* $excluded_files es un archivo de texto donde se encuentran (uno por línea) todos los ficheros
que no pasarán por el procesador. Sólo serán comprimidos y guardados en caché. */

$excluded_files = $basepath.'var/excluded';
/* $definiciones_file es un archivo php que incluiremos cargando las definiciones necesarias para
completar el contenido de los CSS y JS. Puede haber un fichero de definiciones tanto raiz como
en el directorio donde se encuentra el CSS o JS a procesar.*/

$definiciones_file = 'lib/tcjc_defs.php';
/* FIN de Configuración del script */

function gf_getgz_cachefile($file)
{
/* Obtenemos un nombre de fichero único para los archivos de cache */
global $cachedir;
$getstr = $file.sizeof($file).filemtime($file);
$hash = base_convert(md5($getstr),16,36); /* Hash en base36 */

return $cachedir.$hash;
}

function add_ending_slash($path)
{
/* Añade una barra al final de la ruta del directorio */
$sep = (PHP_OS == 'Windows')? '\':'/';
$path .= (substr($path,-1) == $sep)? '':$sep;
return $path;
}

function genera_y_cachea($file, $cachefile)
{
/* Genera el cache, sustituyendo las definiciones */
global $basepath, $definiciones_file, $httppath;

$definiciones = array ('%%http_path%%' => $httppath);
/* Si tenemos un archivo auxiliar para incluir definiciones */
if (file_exists($basepath.$definiciones_file))
require_once($basepath.$definiciones_file);

$local_defs = add_ending_slash(dirname($file)).$definiciones_file;

if (file_exists($local_defs))
require_once($local_defs);

$triggers = array_keys($definiciones);
$reemplaz = array_values($definiciones);
$contenidos = file_get_contents($file);
$contenidos = str_replace($triggers, $reemplaz, $contenidos);
file_put_contents($cachefile, $contenidos);
$gz = gzopen($cachefile.".gz","wb5");
gzwrite($gz, $contenidos);
gzclose($gz);
}

function comprime($file, $cachefile)
{
/* Símplemente comprime el archivo */
$contenidos = file_get_contents($file);

file_put_contents($cachefile, $contenidos); /* Hacemos un backup también */
$gz = fopen($cachefile.".gz","wb");
fwrite($gz, gzencode($contenidos));
fclose($gz);
}

function interpretar($file)
{
/* Mira el archivo de excluidos y si no debo interpretarlo, devuelve false */
global $excluded_files;
if (file_exists($excluded_files))
{
$excl = file ($excluded_files);
return (!in_array($file, $excl)); /* Si la encontramos, devolvemos FALSE */
}
return true;
}

$type = (isset($_GET['type']))?$_GET['type']:false;
$file = (isset($_GET['file']))?$_GET['file']:false;

// Nos aseguramos de que las dos esté especificadas
if (($type) &amp;&amp; ($file))
{

/* Establecemos las cabeceras http necesarias */
switch ($type)
{
case 'css': header("Content-type: text/css; charset=utf-8"); break;
case 'js' : header("Content-type: text/javascript; charset=utf-8"); break;
}
header("Cache-Control: must-revalidate");

if (file_exists($basepath.$file))
{
$origftm = filemtime($basepath.$file);
$cachefile = gf_getgz_cachefile($basepath.$file); /* Genera un nombre de archivo de caché único */

@$destftm = filemtime($cachefile); /* No daremos error si no existe el archivo */

if ($origftm>$destftm)
{
/* Si el fichero original es más nuevo que su caché, lo procesamos todo de nuevo */
if (interpretar($file))
genera_y_cachea($basepath.$file, $cachefile);
else
comprime ($basepath.$file, $cachefile);
}

if ( (isset($_SERVER['HTTP_ACCEPT_ENCODING'])) &amp;&amp; (strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')))
{
header("Content-Encoding: gzip");
header("Content-Length: ".filesize($cachefile.".gz"));
readfile ($cachefile.".gz"); /* Si el navegador permite contenidos gzipeados... */
}
else
readfile ($cachefile);
}
/* else ERROR no existe el fichero CSS o JS */
}
/* else ERROR, no se ha especificado tipo de fichero o el fichero */
?>

También puedes descargarlo directamente: aquí: tcjs.php.gz (2.2Kb)
Lo que pretendo es que con este script sólo tengamos que copiar el archivo, definir un par de cosas y funcionar, y que sea totalmente transparente, tanto que nos olvidemos de que lo estamos usando.

Para instalarlo, podemos copiarlo en el directorio raiz de nuestro servidor, el ejemplo que muestro es para Apache (y es necesario tener mod-rewrite), y crear un archivo .htaccess que contenga lo siguiente:

1
2
3
4
RewriteEngine On
RewriteBase /
RewriteRule ^(.*\.css) tcjs.php?type=css&amp;file=$1
RewriteRule ^(.*\.js) tcjs.php?type=js&amp;file=$1

También tenemos que prestar atención a las primeras líneas de código del script tcjs.php:

  • $base_directory será el directorio raiz de todos los css, js, definiciones y caches (no es estrictamente necesario que sea de estos últimos). Es decir, si nuestra web está en /home/www/public_http/ no debemos llamar a nada que esté en un nivel inferior (podrán estar dentro de subdirectorios pero a partir de este punto); es más, los CSS y JS estarán por ejemplo en /home/www/public_http/js; en este caso $base_directory=’/home/www/public_http/
  • $httppath será la dirección web de menor nivel que vayamos a llamar; por ejemplo: http://www.midominio.com/
  • $cachedir será el lugar donde creemos los ficheros de caché, este directorio tiene que tener permisos para que el servidor web pueda escribir en él.
  • $excluded_files será el nombre de un archivo cuyo contenido serán todos los ficheros que no queramos que sean procesados, sólo serán comprimidos. Por ejemplo, si el fichero es /home/www/public_http/js/nieve.js y nuestro $base_directory es /home/www/public_http/, el texto que deberíamos incluir en el archivo será js/nieve.js
  • $definiciones_file es la ruta relativa a un archivo PHP que se cargará cuando vayamos a generar un CSS o JS. Puede haber dos tipos de archivo de definiciones, el global, situado en $base_directory.$definiciones_file y el local situado en (el mismo directorio que el archivo CSS a procesar).$definiciones_file. Por ejemplo:
    • $base_directory=’/home/www/public_http/’
    • El fichero JS que cargamos estará en /home/www/public_http/js/mijavascript.js
    • $definiciones_file=’defs/definiciones.php
    • tcjs.php cargará dos ficheros de definiciones situados en /home/www/public_http/defs/definiciones.php y en /home/www/public_http/js/defs/definiciones.php

El fichero de definiciones (que ya hemos visto donde está contendrá un array llamado $definiciones, pero no lo crearemos de nuevo, sino que lo continuaremos, por ejemplo:

1
2
3
4
...
$definiciones['color_base'] = '0ff00f';
$definiciones['ruta_static'] = 'http://estaticos.miservidor.com/';
$definiciones['visibilidad_mensajes'] = ($debug)?'visible':'hidden';

Podemos utilizarlo por ejemplo para definir un color de objeto desde PHP y que el CSS lo incluya (puede que debamos usarlo desde PHP también, por ejemplo para generar una imagen con ese color de fondo); para una ruta de ficheros estáticos en un servidor (normalmente en mi servidor local será otra ruta), para mostrar directamente una capa que está oculta mientras estamos programando algunas opciones en Javascript, y para muchas cosas más.

Barra al final del directorio en PHP: 4 formas a elegir

Lunes, 18 de Enero de 2010 admin Sin comentarios

Cuando queremos representar un directorio; podemos obtenerlo de varias formas: /home/usuario/documentos en *nix o C:\Document and Settings\Usuario\Mis Documentos en Windows. Aunque lo mismo podemos representarlo /home/usuario/documentos/ y C:\Document and Settings\Usuario\Mis Documentos\ (es lo mismo, pero con una barra al final).

El problema en PHP, viene a la hora de llamar archivos de ese directorio, hay ocasiones en las que no sabemos si la variable en donde tenemos almacenado el directorio tiene barra al final o no; entonces debemos hacer alguna función que incluya la barra correspondiente si hace falta.

Estos dos primeros script los he sacado de Jonas John Code Snippets:

1
2
3
4
5
6
7
8
9
10
11
12
function add_ending_slash($path){
 
    $slash_type = (strpos($path, '\')===0) ? 'win' : 'unix';  
    $last_char = substr($path, strlen($path)-1, 1);
 
    if ($last_char != '/' and $last_char != '\') {
        // no slash:
        $path .= ($slash_type == 'win') ? '\' : '/';
    }
 
    return $path;
}
1
2
3
4
5
6
7
8
9
10
11
12
function normalize_path($path){
 
    // DIRECTORY_SEPARATOR is a system variable
    // which contains the right slash for the current
    // system (windows = \ or linux = /)
 
    $s = DIRECTORY_SEPARATOR;
    $path = preg_replace('/[\/\\\]/', $s, $path);
    $path = preg_replace('/'.$s.'$/', '', $path) . $s;
 
    return $path;
}

Para este último, tenemos que hacer antes:

1
define("DIRECTORY_SEPARATOR", (PHP_OS=='Windows') ? '\':'/';

Otras dos alternativas:

1
2
3
4
5
6
function ending_slash($path)
{
  $sep = (PHP_OS == 'Windows')? '\':'/';
  $path .= (substr($path,-1) == $sep)? '':$sep;
  return $path;
}
1
2
3
4
5
6
7
function ending_slash2($path)
{
  $sep = (PHP_OS == 'Windows')? '\':'/';
  if ($path)
    $path .= ($path[strlen($path)-1] == $sep)? '':$sep;
  return $path;
}

La última no es muy elegante, pero ahí queda. Las dos últimas son muy parecidas entre sí. Y es una función interesante para nuestra biblioteca de funciones particular.

Categories: PHP Tags: , , , , ,

Pecados capitales: ORDER BY RAND() cuando sólo queremos una fila

Martes, 8 de Diciembre de 2009 admin 1 comentario

Cometí el error cuando estrené las aplicaciones de frases en Facebook de utilizar la siguiente sentencia SQL para sacar una frase aleatoria:

1
SELECT * FROM `frases` ORDER BY RAND() LIMIT 1;

Al principio funcionaba bien, la verdad es que no confiaba mucho en el crecimiento de la aplicación, por lo que dejé el código así. Pero al cabo de unos días, noté que mi proveedor de hosting desactivó mi cuenta por excesivo uso de CPU: el rápido crecimiento de usuarios y frases dentro de la aplicación causaron un uso exponencial de CPU en mi servidor.
Al principio no parece lógico pero si nos fijamos en lo que estamos haciendo con esta línea:

  • Ordenamos de forma aleatoria la tabla frases (normalmente es más pesado que ordenar por fecha, o por un entero)
  • Escoger el primero de la lista obtenida (esto ya no cuesta nada)

Es decir, estamos ordenando la lista por completo (de unas 2000 frases) cada vez que un usuario quiere consultar sólo 1. Por lo que al final (imaginémonos unos 30000 usuarios a la hora), hacemos muchas ordenaciones innecesarias que aumentan el uso de CPU.

Una buena solución podría ser extraer el total de filas que tenemos en la tabla (es más, no tendremos que extraerlo siempre, sino cuando añadamos o borremos información), es una consulta bastante ligera; y luego extraer un sólo elemento empezando por la fila obtenida al azar.
En el siguiente ejemplo propongo un código en PHP que obtiene una fila aleatoria de una tabla (estas líneas las extraigo de un proyecto más grande, por lo que se podrían simplificar un poco más):

1
2
3
4
5
6
$sql="SELECT COUNT(id) FROM `frases`";
$res=mysql_fetch_row(mysql_query($sql));
// Tenemos en $res[0] el número de filas
$num=rand(0, $res-1); // Obtenemos un número aleatorio.
$sql="SELECT * FROM `frases` LIMIT ".$num.",1";
$frase_elegida=mysql_fetch_array(mysql_query($sql));

He dejado un poco de lado las comprobaciones y he dado por hecho que en la tabla frases hay algún contenido. Pero creo que queda bastante clara la idea.

Puede haber más soluciones, pero creo que con esta tenemos más control sobre los resultados (podemos introducir condiciones al número y más cosas).

Categories: MySQL, PHP Tags: , , , , ,

Obtener el sexo en Facebook

Sábado, 5 de Diciembre de 2009 admin Sin comentarios

Probablemente cuando hacemos nuestra aplicación para Facebook queremos personalizar el mensaje hacia el usuario; es decir, escribir estimado o estimada, ya sea hombre o mujer nuestro usuario; en lugar de estimad@ (que quedaba muy bien hace una década, pero ahora deja que desear).

Facebook, desde su plataforma nos da opciones para conseguir esa información, pero hay un problema: están localizadas (es decir, que para español devolverá masculino o femenino; en inglés, male o female y en otros idiomas ya ni os cuento. Pero hay una forma para obtener siempre la información en el mismo idioma (ejemplo en PHP):

1
2
$camposfql = "uid, name, first_name, last_name, pic, sex";
      $userinfo = $facebook->api_client->call_method('facebook.users.getInfo', array('uids' =>$user_id, 'fields' => $camposfql, 'locale' => "en_US"));

Con esto en $userinfo tendremos la información de uid, nombre, avatar y sexo del usuario con id $user_id y si un campo permite localización (como sex), lo dará en inglés de EEUU. Podemos estar seguros de que sex tendrá como valor male o female (o ninguno, si el usuario ha puesto como privado ese dato).
Podemos ver el resultado en esta aplicación: Qué Malo es Pensar:

http://apps.facebook.com/quemaloespensar

http://apps.facebook.com/quemaloespensar

Categories: Interneteando, PHP, facebook Tags: , , ,

Fórmulas de OpenOffice.org Calc en inglés

Jueves, 3 de Diciembre de 2009 admin Sin comentarios

Algunos, estemos programando o tengamos que hacer unas cuantas fórmulas para OpenOffice.org Calc, nos sentimos más cómodos programando en inglés. Además de por la costumbre, porque la mayor parte de la referencia que encontremos estará en este idioma.

Es verdad que los desarrolladores de OpenOffice, quieren que muchas cosas se parezcan a MS Office y hacen una localización completa del programa, está muy bien; como también lo estaría poner un checkbox en las opciones para seleccionar si queremos las fórmulas localizadas o no.

OpenOffice Calc Pero si miramos en Environment Variables - OOo Wiki podemos observar una variable de entorno en concreto: OOO_CALC_USE_ENGLISH_FORMULAS válida para todos los SSOO. Para utilizarlo en Linux tenemos varias posibilidades:

Ejecutar desde consola:

$OOO_CALC_USE_ENGLISH_FORMULAS=1 soffice

Por ejemplo, Gentoo, cuando se instala OpenOffice.org crea también accesos directos por consola, para Calc tenemos oocalc, es un script para bash localizado en /usr/bin (which oocalc) en cuyo código insertamos una línea (muestro lo insertado con comentarios):

1
2
3
4
5
6
7
#!/bin/sh

#Nueva línea para tener las fórmulas en inglés
export OOO_CALC_USE_ENGLISH_FORMULAS=1
#Fin de la nueva línea para tener las fórmulas en inglés
cmd=`dirname "$0"`/soffice
exec "$cmd" -calc "$@"

Esta nueva línea también la podemos poner en .bashrc para no tener que reeditar oocalc cuando actualicemos la versión.

También tenemos que tener en cuenta que es una medida experimental por lo que puede ser que tenga algún fallo que debamos reportar.

Categories: General, PHP Tags:

Geolocalización de una IP

Domingo, 26 de Julio de 2009 blakeyed Sin comentarios

A veces, nos es de bastante utilidad geolocalizar a un visitante, bien puede ser para mostrarle una publicidad relevante o porque prestamos un servicio que sólo existe en determinados países, para escoger automáticamente el idioma de nuestra web, o por motivos estadísticos, para saber de dónde provienen nuestras visitas, como medida en una red social para detectar automáticamente dónde estás… en fin, hay un sinfín de utilidades.

Lo más común para geolocalizar a los visitantes es verificar su dirección IP y consultar en una base de datos a qué país pertenece. Hay empresas que comercializan estas bases de datos, y las hay con mucha precisión (algunas pueden decirnos hasta la ciudad donde está conectada la persona con esa dirección IP). Aunque vengo a hablaros de un servicio gratuito: Ip to Country de Webhosting.info.

En las web citada viene mucha información de cómo utilizar la base de datos y código de ejemplo, por lo que no me extenderé mucho.

En resumen, tenemos que decargar el fichero CSV, que contiene la tabla que debemos incluir en nuestra base de datos (por ejemplo, PhpMyAdmin tiene la posibilidad de importar ficheros CSV). Seguidamente, hay que tener en cuenta que en esta tabla, la IP no está en el formato que estamos acostumbrados (4 números de 8bits separados por puntos), está en formato long, lo que es los 32bits (en PHP podemos hacer la conversión con ip2long()). Para hacer nuestro programa hemos de saber que la IP que queremos geolocalizar tiene que estar comprendida entre ip_from (primera ip que viene en la tabla) e ip_to (segunda ip).

Categories: PHP Tags: , , , , ,

Conseguir la IP del usuario

Viernes, 24 de Julio de 2009 blakeyed 2 comentarios

Os dejo el código:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function gf_obtiene_ip () {
  // Las variables _SERVER nos lo pueden decir
  $metodos = array("CLIENT_IP","HTTP_X_FORWARDED_FOR","HTTP_X_FORWARDED","HTTP_FORWARDED_FOR","HTTP_FORWARDED","REMOTE_ADDR");

  $i = 0;

  while ( ($i<count($metodos) ) || (!isset($ip) ) )  
    {
      $valor = $metodos[$i];
      if (isset($_SERVER[$valor]))
    $ip =$_SERVER[$valor];
      else if (isset($_ENV[$valor]))
    $ip =$_ENV[$valor];

      $i++;
  }
  return ( isset($ip) ) ? $ip: false;
}

Con este script intentamos evitar que se detecte como la IP del usuario la de un proxy intermedio recorriendo todas las variables que podemos encontrar en $metodos.

Categories: PHP Tags: , , ,

Plantillas de correo dinámicas automáticas en Thunderbird

Domingo, 12 de Julio de 2009 blakeyed Sin comentarios
Nuevo mensaje en Mozilla Thunderbird

Nuevo mensaje en Mozilla Thunderbird

Me pareció casi increíble que Mozilla Thunderbird no pudiera incluir plantilas en los e-mails automáticamente de serie. (Es cierto que soporta plantillas, pero tienes que pulsar en la plantilla antes de crear el mail).

Afortunadamente, encontré hace tiempo la extensión ExternalTemplateLoader de Kaosmos. Nos introducir una plantilla que se cargará automáticamente cuando redactemos/respondamos/reenviemos un mensaje.  Pero además, esa plantilla podemos cargarla desde un archivo local o alojada en un servidor de Internet. Con lo cual podremos también, crear plantillas dinámicas.

Para hacer plantillas dinámicas, tenemos varias posibilidades:

  • Si lo que queremos hacer dinámico es cambiar una frase, un texto, una foto que cambie cada cierto tiempo, podemos crear un cron job que genere el archivo html de plantilla cada cierto tiempo, eso nos ahorraría tener que generar la plantilla cada vez que vamos a escribir un mail.
  • Si queremos monitorizar algo, crear un identificador por cada email que vayamos a enviar, escribir un informe, contabilizar los mails, etc; no queda más remedio que generar la plantilla cada vez que vayamos a redatar un mail.

En futuros posts incluiré ejemplos de cada uno de los métodos.

Sigo probando…

Jueves, 21 de Mayo de 2009 blakeyed Sin comentarios

Acabo de instalar el plugin Code Highlighter para WordPress que utiliza la clase GeSHi de PHP para colorear código fuente y contar las líneas, algo importante para mí.

Aquí muestro algunas pruebas, tal vez no sirvan para nada, pero bueno.

Un poco de C:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include

int main(int argc, char* argv[])
{
  int i;
  printf("Hola mundo!\n\n");
  if (argc>1)
  {
    printf ("Me has pasado: %d parámetros, qué bien!\n", argc);
    printf ("Ahora te los voy a decir:\n");
    for (i=1; i<argc; i++)
    {
      printf("Parametro %d: \"%s\"\n", i, argv[i]);
    }
  }
  printf("\nEl programa llega a su fin\n\n");
}

Y ahora un poco de PHP:

1
2
3
4
<?
echo "Hola Mundo!".nl2br("\n");
echo "Por si no lo sabes, soy ".$_SERVER['PHP_SELF'];
?>

Bueno, con esto terminaré de configurar algunos plugins, y ya me pondré a publicar en serio :)

Gracias por vuestra paciencia :)

Easy AdSense by Unreal