miércoles, 11 de junio de 2014

¿Qué día me dijiste que teníamos la reunión? (Manejo de fechas en SQLite3)

Como dicen en la propia documentación de SQLite, en SQLite3 no existe el tipo de datos fecha.

Cito directamente de http://www.sqlite.org/datatype3.html


1.2 Date and Time Datatype

SQLite does not have a storage class set aside for storing dates and/or times. Instead, the built-in Date And Time Functions of SQLite are capable of storing dates and times as TEXT, REAL, or INTEGER values:

    TEXT as ISO8601 strings ("YYYY-MM-DD HH:MM:SS.SSS").
    REAL as Julian day numbers, the number of days since noon in Greenwich on November 24, 4714 B.C. according to the proleptic Gregorian calendar.
    INTEGER as Unix Time, the number of seconds since 1970-01-01 00:00:00 UTC.

Applications can chose to store dates and times in any of these formats and freely convert between formats using the built-in date and time functions.

Así que lo más conveniente es declarar el tipo de ese campo como TEXT (o números, también vale), almacenar las fechas en el formato ISO8601 (básicamente: 'YYYY-MM-DD HH:MM:SS'), así además se puede ordenar por ese campo simplemente ordenando como texto, y utilizar las funciones de fecha de SQLite3 para procesarlas.

Por ejemplo, para hacer una comparación:

 1 select * from tabla where julianday(f1) > julianday('2014-01-01 00:00:00')


 

UN EJEMPLO PRÁCTICO


Bien, hasta aquí la teoría. Vamos a probarlo. Para ello, voy a utilizar SQLite Expert Personal, donde he creado una base de datos y dentro de ella crearé una tabla con un campo fecha.

1. Creamos la tabla

 1 CREATE TABLE PERSONAS
 2 (
 3   ID         NUMBER(10)  NOT NULL,
 4   NOMBRE     VARCHAR(30),
 5   APE1       VARCHAR(30),
 6   APE2       VARCHAR(30),
 7   FNACIM     DATETEXT  
 8 );

El tipo de dato DATETEXT (línea 7) se corresponde internamente en SQLite Expert con WideString, pero en realidad debería valer cualquier tipo de datos de texto.

2. Insertamos unos cuantos datos de ejemplo

 1 insert into PERSONAS(ID, NOMBRE, APE1, APE2, FNACIM) values (1, 'MARIANO', 'RAJOY', 'ZAPATERO', '1965-05-20');
 2 insert into PERSONAS(ID, NOMBRE, APE1, APE2, FNACIM) values (2, 'JOSE LUIS', 'RAJOY', 'ZAPATERO', '1970-06-20');
 3 insert into PERSONAS(ID, NOMBRE, APE1, APE2, FNACIM) values (3, 'PETER', 'SCHWARZENEGGER', NULL, '1973-08-30');
 4 insert into PERSONAS(ID, NOMBRE, APE1, APE2, FNACIM) values (4, 'ARNOLD', 'LANDA', 'CLARK', '1982-08-30');

Antes de consultar nada, comprobamos que los datos se han insertado bien, yéndonos a la pestaña "Data" de SQLite Expert
Fig. 1. Los datos. Cuántos conocidos por aquí.


3. Hacemos una consulta 

En ésta, utilizamos la función "julianday" para comparar fechas

 1 SELECT * FROM PERSONAS WHERE julianday(FNACIM) > julianday('1970-07-01')


El resultado:
Fig. 2. Resultado de la consulta. Los más jovencitos del grupo


Bueno, parece que todo ha ido bien.

Además de juliandate, SQLite incorpora otras cuatro funciones para trabajar con fechas: date, time, datetime y strftime. Os recomiendo la lectura de la página donde se describen (enlace al final).

Una vez que se sabe esta forma de trabajar con las fechas en SQLite3, la cuestión parece una tontería, pero el hecho de que SQLite no tuviera un tipo de dato nativo para las fechas me ha hecho perder un buen rato. Espero que no le pase a quien lea esto.

¿Y tú, te has peleado con fechas en SQLite?

Más info:

SQLite. http://www.sqlite.org/

Funciones de fecha en SQLite. http://www.sqlite.org/lang_datefunc.html

SQLite Expert Personal. Un estupendo gestor de bases de datos SQLite. http://www.sqliteexpert.com/download.html

jueves, 5 de junio de 2014

Recorrer un directorio en PHP procesando los ficheros en su interior

Vamos a ver un pequeño ejercicio en el que recorreremos un directorio contando cuántos ficheros hay colgando de él, incluyendo los de sus subdirectorios. Esto es un paso hacia una herramienta un poco más ambiciosa. Pero empecemos por el primer paso...


1. Funciones de Directorios en PHP

Hay tres funciones que son claves para recorrer un directorio con PHP.

La primera, opendir, toma el nombre del directorio a leer (sin la barra del final) y devuelve un identificador del directorio, que se podrá usar con las otras funciones. Llamada:

    $dir = opendir($path)

La segunda, readdir, va devolviendo en sucesivas llamadas los nombres de las entradas contenidas en el directorio. Normalmente, esto se utiliza en un bucle de la forma

    while ($elemento = readdir($dir)){
        ...procesar
    }

Hay que tener cuidado con los dos directorios especiales "punto" (actual) y "punto punto" (superior), más conocidos como "." y "..". Normalmente, al procesar los elementos del directorio se controla con un if si el elemento a tratar no es ninguno de estos dos. Algo así:

    $dir = opendir($path)
    while ($elemento = readdir($dir)){
        if( $elemento != "." && $elemento != ".."){
            ... procesar
        }   
    }

Por último, para diferenciar si el elemento a tratar es un fichero o es un subdirectorio, tenemos la función is_dir. En caso de que sea un subdirectorio al que queramos aplicar el mismo tratamiento que al actual, podemos hacer una llamada recursiva a la misma función (que aquí llamaremos analizar_directorio).


2. Todo Junto

Pongámoslo ahora todo junto, en una función que se limita a contar los ficheros contenidos en el directorio inicial y los subdirectorios que hay dentro, recorridos de manera recursiva (¡ojo, cuidado con la recursividad). Más adelante haremos cosas más interesantes que contar ficheros. Para probarlo todo, guardaremos el siguiente listado como index.php:

 1 <html>
 2 <head>
 3     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 4 </head>
 5 
 6 <body>
 7 <?php
 8     $path = "../../rips";
 9     $total_ficheros = analizar_directorio($path);
10     echo "Hay $total_ficheros ficheros en el directorio $path<br>";
11     
12 //------------------------------------------------------------- 
13 function analizar_directorio($path) {
14     $total_ficheros = 0;
15     $dir = opendir($path);
16     while ($elemento = readdir($dir)){
17         if( $elemento != "." && $elemento != ".."){
18             // Si es una carpeta
19             if( is_dir($path."/".$elemento) ){
20                 // Muestro la carpeta
21                 echo("Procesando subdirectorio: ". $elemento . "<br>");
22                 $total_ficheros += analizar_directorio($path."/".$elemento);
23             // Si es un fichero
24             } else {
25                 $total_ficheros++;
26             }
27         }
28     }
29     return $total_ficheros;
30 }
31 
32 ?>


El resultado en el navegador:


Referencias sobre las tres funciones

http://www.php.net/manual/es/function.opendir.php
https://php.net/manual/es/function.readdir.php
https://php.net/manual/es/function.is-dir.php

martes, 3 de junio de 2014

Configurar Apache con PHP en Ubuntu Linux

Guía breve, breve, brevísima, para recordar los pasos que he dado para la instalación, pero sin muchas explicaciones.

1. Instalar Apache

$ sudo apt-get install apache2

2. Instalar PHP, versión 5 (PHP5)

$ sudo apt-get install php5

$ sudo apt-get install libapache2-mod-php5


3. Habilitar el módulo de PHP5 en Apache

$ sudo a2enmod php5


Y ya podemos probarlo con un sencillo fichero de prueba, por ejemplo:

Fichero index.php:

 1     <HTML> 
 2     <H1>Probando PHP</H1>
 3     Salida del comando phpinfo:
 4     <?php
 5         phpinfo();
 6     ?>
 7     </HTML>
Listado 1. El HTML no es perfectamente ortodoxo, pero sólo es una prueba

¡Ojo! En la línea 4 del anterior código, la instrucción de apertura del código PHP, es decir
   
    <?php

    en teoría también debería funcionar si se omiten las letras "php", es decir
   
    <?
   
Bueno, pues resulta que esto sí que me ha funcionado en Apache2 sobre Windows XP, pero en Ubuntu me ha tenido un ratico dándole vueltas a la cabeza, pues no funcionaba, y me mostraba, en vez de la salida de la función phpinfo(), el texto hasta la línea 3, y el resto de la página en blanco. Es decir, como si no interpretara la función phpinfo(), e ignorara todo lo situado entre las etiquetas "<?" y "?>". Al final se ha arreglado cuando a la etiqueta de apertura le he añadido esas tres letras, dejándola así: "<?php" (sin las comillas, claro). Así que cuidado con este detalle, pues os puede hacer creer que PHP no está funcionando cuando en realidad sí que está bien instalado.

Directorios de interés
Fichero de configuración de Apache2
/etc/apache2/apache2.conf

Directorio por defecto para publicación de contenidos
/var/www/html

Más info
http://doc.ubuntu-es.org/HTTPD_Servidor_web_Apache2
Bien explicada, con muchísimos detalles y sin molestos banners publicitarios.
Related Posts Plugin for WordPress, Blogger...