jueves, 18 de septiembre de 2014

[Parte 7] PHP

Cookies y Sesiones

Http es un protocolo sin estado por lo cual no puede identificar que usuario es cual, ni darle seguimiento. En PHP existen dos herramientas para este proposito las cookies y las sesiones, con las cuales podemos identificar al usuario y darle seguimiento.

Las diferencias entre las cookies y las sesiones es que las cookies se guardan en el navegador del cliente y las sesiones se guardan en el servidor. Las sesiones son generalmente mas seguras que las cookies y pueden almacenar mucha mas informacion. Ambas son tecnologias faciles de utilizar usando PHP para demostrarlo crearemos un sistema de inicio de sesion.

Crear una pagina de inicio de sesion

El proceso de inicio de sesion envuelve algunos componentes:

* Un formulario envia la informacion de inicio de sesion
* Una rutina de validacion se asegura de que los datos necesarios se han enviado
* Una consulta a la base de datos compara que la informacion enviada sea igual a la informacion almacenada en la base de datos
* Las cookies o sesiones son almacenadas reflejando un inicio de sesion correcto

Subsecuente a esto las paginas pueden tener una restriccion por la cual solo se mostraran a usuarios que hayan iniciado sesion, en las cuales pueden agregar caracteristicas especiales.

Crearemos varios archivos rompiendo la logica y haciendola mas facil para que nuestro codigo sea mas facil de escribir y leer y tenga menos redundancia. El script va contener la pagina de inicio de sesion, la cabecera, el reporte de errores, el formulario y el pie de pagina.

Creamos la pagina de inicio de sesion:

login _page.inc.php



<?php
 # Esta pagina imprime cualquier error y esta asociado con la pagina de inicio
 # Y crea la pagina de inicio de sesion entera, incluyendo el formulario.

 # incluir la cabecera
 $page_title = 'Inicio de sesion';
 include('includes/header.html');

 # Imprime cualquier mensaje de error, si existe:
 if (isset($errors) && !empty($errors)) {
   echo '<h1>Error!</h1>
   <p class="error">Los siguientes errores han ocurrido:<br />';
   foreach ($errors as $msg) {
    echo "- $msg<br />\n";
   }
   echo "</p><p>Por favor intente de nuevo.</p>";
  } 

  # Mostrar el formulario:
?>
<h1>Iniciar sesion</h1>
<form action="login.php" method="post">
 <p>Correo electronico: <input type="text" name="email" size="20" maxlength="60" /></p>
 <p>Clave: <input type="password" name="pass" size="20" maxlength="20" /></p>
 <p><input type="submit" name="submit" value="Iniciar sesion!" /></p>
</form>
<?php 
 include('includes/footer.html');
?>


1.- Incluimos el header.html y el titulo al inicio (el header.html lo veremos mas adelante)

2.- Si ocurre algun error imprimimos el error recorriendolo con foreach
3.- Mostramos el formulario
4.- Incluimos footer.html

Nota: estamos utilizando .inc.php para los archivos que iran dentro de otros archivos (seran incluidos), y tambien crearemos una carpeta llamada includes/ donde se encontraran cada uno de ellos.

En el proceso de la creacion de la pagina de inicio de sesion, hay 2 cosas que se repiten, las cuales son :

- Verificacion de correo electronico y clave en la base de datos
- Redirecciones

Es por eso que para comenzar crearemos un script php con el cual evitaremos la redundancia del codigo, nuestro script se llamara login_functions.inc.php:


<?php
 # Esta pagina define dos funciones usadas para el inicio y cierre de sesion
 /*
  Esta funcion determina la URL absoluta y redirige al usuario
  * Esta funcion toma un argumento para que sea redirigido
  * El argumento por defecto es index.php
 */
 function redirect_user ($page = 'index.php'){
  // comienza definiendo la url
  // la url es http:// agregando el nombre del host y el directorio actual
  $url = 'http://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']);

  // remueve cualquier barra invertida
  $url = rtrim($url,'/\\');

  // Agrega la pagina:
  $url .= '/' . $page;

  // Redirige al usuario:

  header("Location: $url");
  exit(); // Quita el script
 } // Fin de la funcion redirect_user()

 /*
  Esta funcion valida los datos del formulario (el correo electronico y la clave).
  * Si ambos estan presentes, la base de datos es consultada
  * La funcion requiere coneccion a la base de datos
  * La funcion devuelve un arrat de informacion, incluyendo:
   -  Una variable TRUE/FALSE que indica si fue correcto
   - Un array para los errores o resultados de la base de datos
 */
 function check_login($dbc,$email='',$pass=''){
  $errors = array(); // Inicializamos un array de errores

  // Validamos el correo electronico
  if (empty($email)) {
   $errors[] = 'Olvidastes poner el correo electronico';
  }else{
   $e = mysqli_real_escape_string($dbc,trim($email));
  }
  // Validamos la clave
  if (empty($pass)) {
   $errors[] = 'Olvidastes poner la clave';
  }else{
   $p = mysqli_real_escape_string($dbc,trim($pass));
  }

  if(empty($errors)){
   // Si todo esta bien
   // Devolvemos el id de usuario, el primer nombre de usuario con la combinacion de
   // correo electronico/clave

   $q = "SELECT user_id, first_name FROM login WHERE email='$e' AND pass=SHA1('$p')";
   $r = @mysqli_query($dbc,$q);
   // Correr la consulta
   // verificamos el resultado

   if (mysqli_num_rows($r) == 1) {
    // devolvemos los registros
    $row = mysqli_fetch_array($r,MYSQLI_ASSOC);
    // devuelve true y los registros:
    return array(true,$row);

   }else{ // No coincide
    $errors[] = 'El correo electronico y la clave no coinciden con el archivo';
   }
  } // final de si empty($errors)
  // devuelve falso y los errores:
  return array(false,$errors);
 } // final de la funcion check_login().
?>

Explicando un poco el codigo:

La primera funcion:

1.- Creamos una funcion redirect_user() con la cual podemos redirigir a los usuarios a la pagina que le demos como parametro, pero por defecto es index.php

2.- Creamos la variable $url la cual contiene, primero agregamos el http:// por si nos encontramos en localhost, despues el host seria la url actual, al final agregamos el directorio actual del archivo donde nos encontramos con PHP _SELF.

3.- Removemos las barras

4.- Agregamos la pagina que le dimos para redirigir a la variable $url

5.- Redirigimos a la $url final con header()

6.- Paramos el script con exit()

La segunda funcion:

1.- Se crea la funcion check_login() que lleva tres argumentos, la coneccion a la base de datos, el correo electronico (este es opcional) y la clave (tambien es opcional).

2.- Validamos el correo y la clave, si algun problema ocurre mostrara los errores.

3.- Verificamos que el correo y la clave sea correcta esto lo hacemos de manera que si arroja 1 resultado significa que lo es. Luego devolvemos el resultado en un array como verdadero.

4.- Si el resultado no es correcto devolvemos el array en falso y el inicio de sesion fallará.


Usando Cookies

Las cookies es una forma de que el servidor guarde informacion en la maquina del usuario. Esta es una forma de que el servidor recuerde o siga al usuario. Piensa que la cookie es como un identificador personal, en la cual tu llamas al servidor con tu nombre y el te da una identificacion (pasé o pulsera). Entonces con eso ya sabe a quien se esta refiriendo. En este apartado veremos como establecer una cookie, devolver informacion almacenada por la cookie, alterar la configuracion de la cookie, y tambien eliminar la cookie.


Establecer cookies

La cosa mas importante para aprender acerca de las cookies es que ellas son enviadas desde el servidor hasta el cliente antes que cualquier otra informacion. Ya que si envias una cookie despues esto causaria un error. Incluso si es un espacio en blanco.

Las cookies se envian con la funcion setcookie():

setcookie('nombre','valor');

setcookie('nombre','arthusu');


Como ves esto enviaria una cookie al navegador de nombre le pusimos nombre (valga la redundancia) y de valor le pusimos arthusu. De igual manera si quisieramos agregar mas cookies solamente las seguimos estableciendo con la misma funcion:

setcookie('ID',250);
setcookie('email','arthusu@gmail.com');

Es recomendable no utilizar espacios ni puntuaciones en el nombre establecido.

Veamos como establecer una cookie utilizando todo el codigo del ejemplo anterior...

login.php


<?php
 // esta pagina procesa el formulario de inicio de sesion
 // si el inicio de sesion es correcto, el usuario es redirigido
 // tenemos que incluir dos archivos necesarios
 // no enviamos nada al navegador antes de las lineas setcookie()

 // checamos si el formulario ha sido enviado:
 
 if ($_SERVER['REQUEST_METHOD'] == 'POST') {
  // para procesar el inicio de sesion
  require('includes/login_functions.inc.php');

  // necesitamos la coneccion a la base de datos:
  require('../mysqli_connect.php');

  // verificamos el inicio de sesion:
  list($check,$data) = check_login($dbc,$_POST['email'],$_POST['pass']);
  if ($check) { //OK
   setcookie('user_id',$data['user_id']);
   setcookie('first_name',$data['first_name']);

   // redirigimos
   redirect_user('loggedin.php');
  }else{ // No es correcto
   // asignamos a $data para $errors para que nos muestre los errores
   // en el archivo login_page.inc.php
   $errors = $data;
  }

  mysqli_close($dbc); // cerramos la coneccion a la base de datos
 } // aqui termina la condicional principal
 
 // creamos la pagina:
 include('includes/login_page.inc.php');

?>


Explicando el codigo anterior:

1.- Creamos la pagina login.php que requiere de los dos archivos que creamos anteriormente para poder funcionar.

2.- Verificamos que el formulario haya sido enviado y si es asi, entonces agregamos dos script el de las funciones por que lo necesitaremos y el de la coneccion a la base de datos, de forma que verificaremos el inicio de sesion y ademas enviaremos las cookies.

Antes de seguir agregare el codigo de los demas archivos que nos faltan para poder seguir trabajando con nuestros scripts:

1.- Vamos a crear la base de datos la cual llamaremos "usuarios", esto lo hacemos ingresando a phpmyadmin:
http://localhost/phpmyadmin/

2.- Donde dice crear nueva base de datos, colocamos y nombre y le damos crear.

3.- Creamos una nueva tabla dentro que se va llamar login, en la cual agregaremos 5 campos los cuales seran:

* user_id (int not null autoincrement primary key)
* first_name (varchar 70 not null)
* last_name (varchar 70 not null)
* email (varchar 20 not null)
* password (varchar 40 not null)



4.- Insertamos un nuevo registro dando clic en insertar, ahi llenamos los datos, en mi caso puse lo siguiente :

user_ id : 1first_name:  arthusulast _name:  xdemail: arthusu@gmail.compassword: utilize la funcion sha1 y puse clave 123

El archivo php para la coneccion a la base de datos la tenemos fuera del directorio publico de manera que nadie mas lo podra ver a menos que tengan permisos:

mysqli_connect.php


<?php
 
 // Este archivo contiene acceso a la informacion de la base de datos
 // Esta archivo tambien establece coneccion con MySQL
 // selecciona la base de datos, y establece una codificacion

 
 // establecemos la informacion en constantes:
 define('DB_USER', 'tusuario');
 define('DB_PASSWORD', 'tucontraseña');
 define('DB_HOST', 'localhost');
 define('DB_NAME', 'usuarios');

 // creamos una coneccion:
 $dbc = @mysqli_connect(DB_HOST,DB_USER,DB_PASSWORD,DB_NAME) OR die('No se pudo conectar a MySQL: '.mysqli_connect_error());

 // esablecemos la codificacion:
 mysqli_set_charset($dbc,'utf-8');
?>

En el codigo del archivo anterior definimos en constantes los datos para una coneccion, con mysqli_connect() establecemos una coneccion con la base de datos con mysqli_set_charset() establecemos una codificacion para la base de datos.


El archivo header y footer son los siguientes: 

header.html


<!DOCTYPE html>
<html>
<head>
 <title><?php echo $page_title; ?></title>
 <link rel="stylesheet" href="includes/styles.css" type="text/css" media="screen" />
 <meta http-equiv="content-type" content="text/html;charset=utf8" />
</head>
<body>
 <header>
  <h1>Tu sitio web</h1>
  <h2>Tu slogan...</h2>
 </header>
 <nav>
  <ul>
   <li><a href="#">Inicio</a></li>
   <li><a href="#">...</a></li>
   <li><a href="#">...</a></li>
   <li><a href="#">...</a></li>
   <li><a href="#">...</a></li>
  </ul>
 </nav>



footer.html
 <footer>
  <p><b>Copyright 2014</b></p>
 </footer>
</body>
</html>


Ya terminado nuestro codigo para continuar con la explicacion con el codigo de las cookies, por cierto el estilo no se ha agregado, esto lo veremos mas adelante...

3.- Validamos los datos enviando estableciendo la coneccion a la base de datos, y los datos que se pasan que estan en el formulario. Como en la funcion check_login() devolvemos un array entonces lo recojemos en variables utilizando la funcion list(). De esta manera sabremos si el login es correcto o no, y asi poder utilizar los datos.

4.- Si el inicio de sesion es correcto, establecemos las cookies user_id y first_name para ello utilizaremos los datos de la base de datos arrojados por la funcion check_login(). Y haremos una redireccion a un archivo que todavia no existe llamado loggedin.php

5.- Si el inicio de sesion no es correcto arrojamos los errores.

6.- Cerramos la base de datos utilizando mysqli_close(). Incluimos el archivo que contiene nuestro formulario.


De todas formas aunque el archivo loggedin.php no exista en los navegadores podemos ver como las cookies se han establecido correctamente:



Algunas notas importantes sobre las cookies es que estan limitadas a 4KB y que cada navegador recuerda un numero limitado de cookies para cada sitio. Los mayoria de los navegadores actuales soportan hasta 50 cookies por sitio. La funcion setcookie() es una de las pocas funciones en php que podria tener diferentes resultados en diferentes navegadores, desde cada navegador las cookies son tratadas de diferente manera. Para estar seguros podemos probar nuestro sitio web en diferentes navegadores y diferentes plataformas.

Accediendo a las cookies

Para devolver una valor desde la cookie, tu solo debes referirte al array superglobal $_COOKIE, usando apropiadamente el nombre de la cookie como clave, por ejemplo para devolver el valor de una cookie establecida:


setcookie('username','arthusu');

tu puedes referirte a ella como $_COOKIE['username']




<?php
 // el usuario es redirigido aqui desde login.php
 
 // si la cookie no esta presente, redirigimos al usuario
 if (!isset($_COOKIE['user_id'])) {
  // necesitamos las funciones
  require('includes/login_functions.inc.php');
  redirect_user();
 }

 // establecemos el titulo de la pagina en la cabecera html
 $page_title = 'Sesion iniciada';
 include('includes/header.html');

 // mostramos un mensaje personalizado

 echo "<h1>Sesion iniciada correctamente</h1>
 <p>Tu sesion esta iniciada como, {$_COOKIE['first_name']}!
 <a href=\"logout.php\">Salir</a></p>";

 include('includes/footer.html');
?>

1.- verificamos si existe la cookie, en caso de no existir redirigimos al inicio de la pagina. Antes para ello es necesario agregar donde se encuentran las funciones para llamar a la pagina y redirigir.

2.- Si el inicio de sesion es correcto, creamos una variable con el titulo e incluimos el header.html el cual contiene un codigo para nuestra variable. Despues de eso mostramos un mensaje de bienvenida con el nombre del usuario haciendo referencia a el con el array superglobal $_COOKIE.

3.- Creamos un enlace de Salida (logout.php) que mas adelante veremos como crear.

Estableciendo parametros a las cookies

Nosotros solo hemos pasado el nombre y el valor como parametros en la funcion setcookie(), pero hay otros argumentos disponibles que puede tomar y cada uno altera la definicion de la cookie.


setcookie(nombre,valor,expiracion,ruta,servidor,secure,httponly)

El argumento expiracion es usado para establecer el tiempo de duracion para que una cookie exista. Este tiempo se especifica en segundos. Si este valor se deja en 0 no se especifica nada y la cookie es eliminada hasta que el navegador es cerrado. Podremos agregar un tiempo de expiracion especifico utilizando la funcion time(), por ejemplo si quisieramos agregar 30 minutos en tiempo de expiracion de la cookie seria de la siguiente manera:


setcookie(nombre,valor,time()+1800);

Donde 1800 es el tiempo en segundos.
La ruta y el servidor son usados para limitar la cookie a una ruta especificada o servidor, por ejemplo: www.ejemplo.com o 192.168.0.1. Y en la ruta por ejemplo si tu quieres que esa cookie solo exista en la ruta del administrador admin/ se la especificas ahi mismo.
Si nosotros establecemos en la ruta / se podra usar la cookie en todo el sitio, y si ponemos en el servidor .ejemplo.com se puede usar la cookie en todo el sitio y subdominios.

El valor secure dice que la cookie solo puede ser enviada por conecciones seguras https. Con 1 la activamos y con 0 dejamos la coneccion estandar. En caso de que tu sitio tenga activado https puedes activar para que las cookies sean seguras estableciendo el valor 1.


setcookie(nombre,valor,expiracion,ruta,servidor,1);
En la version de php 5.2 fue agregado el argumento httponly. Este es un valor Booleano que es usado para crear una cookie accesible mediante HTTP (y HTTPS). Reforzando la restriccion de la cookie haciendola mas segura (ante intentos de hackers) pero no es soportada por todos los navegadores. 


setcookie(nombre,valor,expiracion,ruta,servidor,secure,TRUE);

Como la mayoria de las funciones en setcookie() para no establecer ninguna valor a alguno de los parametros solo es necesario utilizar NULL, 0 o una cadena vacia (No usar FALSE). La expiracion y secure ambos son valores enteros por lo cuales no deben ir entre comillas. 

Vamos a demostrar todo lo visto en el script anterior modificando la cookie haciendo que expire en 1 hora.

Abrimos el archivo login.php y le agregamos lo siguiente:


setcookie('user_id',$data['user_id'],time()+3600,'/','',0,0);setcookie('first_name',$data['first_name'],time()+3600,'/','',0,0);




<?php
 // esta pagina procesa el formulario de inicio de sesion
 // si el inicio de sesion es correcto, el usuario es redirigido
 // tenemos que incluir dos archivos necesarios
 // no enviamos nada al navegador antes de las lineas setcookie()

 // checamos si el formulario ha sido enviado:
 
 if ($_SERVER['REQUEST_METHOD'] == 'POST') {

  // para procesar el inicio de sesion
  require('includes/login_functions.inc.php');

  // necesitamos la coneccion a la base de datos:
  require('../mysqli_connect.php');

  // verificamos el inicio de sesion:

  list($check,$data) = check_login($dbc,$_POST['email'],$_POST['pass']);
  if ($check) { //OK
   setcookie('user_id',$data['user_id'],time()+3600,'/','',0,0);
   setcookie('first_name',$data['first_name'],time()+3600,'/','',0,0);

   // redirigimos
   redirect_user('loggedin.php');
  }else{ // No es correcto
   // asignamos a $data para $errors para que nos muestre los errores
   // en el archivo login_page.inc.php
   $errors = $data;
  }

  mysqli_close($dbc); // cerramos la coneccion a la base de datos
 } // aqui termina la condicional principal
 
 // creamos la pagina:
 include('includes/login_page.inc.php');

?>


Para sacar los segundos es tan facil como multiplicar 60 minutos que es una hora por 60 segundos que es 1 minuto.


Eliminar las cookies

Lo ultimo para terminar de saber como se usan las cookies es eliminar una. Ya sabemos que hay cookies que tienen un tiempo de expiracion pero incluso si tu quisieras simplemente salir de alguna pagina y que tu sesion ya no este iniciada por alguna razon podrias cerrar tu sesion eliminado la cookie.

Para eliminar la cookie solo es necesario el nombre, el valor dejarlo vacio y el tiempo de expiracion ponerlo hacia atras el tiempo que le hayas dado. Un ejemplo para eliminar la cookie first_name:


setcookie('first_name','',time()-3600);
Para que todo esto quede mas claro vamos a crear nuestra pagina de logout.php:



<?php
 // esta pagina deja al usuario cerrar sesion
 // si la cookie no esta presente, redirige al usuario:

 if (!isset($_COOKIE['user_id'])) {
  // necesitamos las funciones
  require('includes/login_functions.inc.php');
  redirect_user();
 }else{
  // Eliminamos las cookies:
  setcookie('user_id','',time()-3600,'/','',0,0);
  setcookie('first_name','',time()-3600,'/','',0,0);
 }
 // Establecemos un titulo a la pagina
 $page_title = 'Cerrar sesion';
 include('includes/header.html');

 // Imprimimos un mensaje personalizado

 echo "<h1>Cierre de sesion!</h1>
 <p>Tu cesion ha sido cerrada correctamente, {$_COOKIE['first_name']}</p>";

 include('includes/footer.html');
?>


Usando sesiones

Otro metodo para crear datos disponibles en multiples paginas de un sitio web es utilizar sesiones. La premisa de una sesion es que los datos son almacenados en el servidor, no en el navegador web, y el identificador de sesion es usado para identificar a un usuario en particular (datos de sesion). Este identificador de sesion es almacenado en el navegador comunmente cuando utilizamos cookies, pero los datos son sensibles, como el ID de usuario, el nombre y demas, por eso los datos siempre deben de mantenerse en el servidor.

La pregunta surge aqui: ¿para que usamos sesiones si podemos usar cookies y funcionan correctamente? primero que todo, las sesiones son mas seguras al almacenar los datos en el servidor,y no continua enviando atras y adelante entre servidor y cliente. En segunda tu puedes guardar mas datos en las sesiones. En tercera algunos usuarios rechazan las cookies o simplemente las mantienen apagadas. Mientras que las sesiones estan diseñadas para trabajar con cookies pueden funcionar sin ellas, tambien.

Para demostrar las sesiones y compararlas con las cookies, reescribiremos los scripts creados anteriormente...

Estableciendo sesiones

La mas importante regla respecto a las sesiones es que cada pagina que vayan a llamarlas deben usar la funcion session_start() al comienzo. Esta funcion es llamada en PHP ya sea cuando comienzas una nueva sesion o accedes a una existente. Esta funcion debe ser llamada antes que cualquier cosa sea enviada al navegador.
La primera vez que esta funcion es usada, session_start() intentara enviar una cookie con el nombre PHPSESSID (nombre por defecto de una sesion) y un valor parecido al este 7d9d0e1d7a8e37f6feb9967ac0a5b445 (32 letras hexadecimales, ID de sesion). El por que de este intento para enviar la cookie, session_start() es enviada antes que cualquier dato sea enviado al naveador web, hasta ese caso nosotros podemos usar las funciones setcookie() y header().

Incluso si la sesion ya ha comenzado, los valores pueden ser registrados para la sesion usando la sintaxis normal del array, usando el array superglobal $_SESSION.

1.- abrimos el archivo login.php y reemplazamos las lineas de setcookie() por el siguiente codigo:

session_start();
$_SESSION['user_id'] = $data['user_id'];
$_SESSION['first_name'] = $data['first_name'];
El primer paso para comenzar la sesion. Es que no debe de haber ninguna declaracion echo, inclusion de archivos HTML o espacios en blanco. Para que la funcion session_start() este segura, tambien podriamos ponerla al inicio de todo el script, nuestro array $_SESSION tiene dos pares de claves con sus valores, first_name y user_id.


<?php
 // esta pagina procesa el formulario de inicio de sesion
 // si el inicio de sesion es correcto, el usuario es redirigido
 // tenemos que incluir dos archivos necesarios
 // no enviamos nada al navegador antes de las lineas setcookie()

 // checamos si el formulario ha sido enviado:
 
 if ($_SERVER['REQUEST_METHOD'] == 'POST') {

  // para procesar el inicio de sesion
  require('includes/login_functions.inc.php');

  // necesitamos la coneccion a la base de datos:
  require('../mysqli_connect.php');

  // verificamos el inicio de sesion:

  list($check,$data) = check_login($dbc,$_POST['email'],$_POST['pass']);
  if ($check) { //OK
   session_start();
   $_SESSION['user_id'] = $data['user_id'];
   $_SESSION['first_name'] = $data['first_name'];
   // redirigimos
   redirect_user('loggedin.php');
  }else{ // No es correcto
   // asignamos a $data para $errors para que nos muestre los errores
   // en el archivo login_page.inc.php
   $errors = $data;
  }

  mysqli_close($dbc); // cerramos la coneccion a la base de datos
 } // aqui termina la condicional principal
 
 // creamos la pagina:
 include('includes/login_page.inc.php');

?>

Obviamente el script loggedin.php debe ser modificado ya que esta esperando la precencia de una cookie.

Tips:

Puedes establecer session.auto_start a 1 en el archivo php.ini de esta manera no es necesario agregar session_start() en cada pagina. Aunque esto tambien hace que el servidor este enviando sesion nueva cada vez y solo debe utilizarse cuando sea realmente necesario.



Accediendo a las sesiones

Incluso las sesiones que ya han sido creadas y las variables que ya han sido registradas, tu puedes acceder desde otros scripts a estas variables, esto lo podemos hacer con cada script iniciando la sesion con session_start().

Esta funcion nos da acceso a la sesion anteriormente almacenada (puede leer el PHPSESSID almacenado en la cookie) o crear una nueva sesion si no esta creada. Comprendiendo que si el ID de sesion no es encontrado y un nuevo ID de sesion es generado, ninguno de los datos almacenados en el ID de sesion viejo estaran disponibles. Lo mencionado aqui puede causarte problemas con sesiones, para verificar el valor de el ID de la sesion podemos verlo en una pagina con el paso a debugear.

Asumiendo que no tienes problemas con la sesion, nos referimos a la variable de la sesion, usando $_SESSION['var'], tu podrias referirte a cualquier otro array. 

1.- abrimos el archivo loggedin.php y agregamos al inicio session_start() que debe ser llamada antes que header.html.

2.- reemplazamos $_COOKIE por $_SESSION y guardamos el archivo.






<?php
 // iniciamos la sesion
 session_start();
 // el usuario es redirigido aqui desde login.php
 
 // si la cookie no esta presente, redirigimos al usuario
 if (!isset($_SESSION['user_id'])) {
  // necesitamos las funciones
  require('includes/login_functions.inc.php');
  redirect_user();
 }

 // establecemos el titulo de la pagina en la cabecera html
 $page_title = 'Sesion iniciada';
 include('includes/header.html');

 // mostramos un mensaje personalizado

 echo "<h1>Sesion iniciada correctamente</h1>
 <p>Tu sesion esta iniciada como, {$_SESSION['first_name']}!
 <a href=\"logout.php\">Salir</a></p>";

 include('includes/footer.html');
?>

Tips:

Recuerda que como ya dijimos, si en tu aplicacion no ves los datos de sesion en otra pagina, esto puede ser por que se ha creado una nueva sesion en otra pagina. Para verificar esto podemos comprobar el ID de sesion (mirando los ultimos caracteres comprobando si son iguales) tambien puedes ver el ID de sesion utilizando la funcion session_id():

echo session_id();

Eliminando sesiones

Cuando utilizamos sesiones usted debe de tener un metodo para poder eliminarlas, esto es necesario para que el usuario cierre sesion. 
Para eliminar una variable de sesion individual podemos utilizar la funcion unset() que es valida para cualquier variable:

 unset($_SESSION['var'])

Para eliminar cualquier variable de la sesion tu no deberias utilizar unset() sino reestablecer la sesion de la siguiente manera:

$_SESSION = array();

Y finalizamos borrando cualquier dato de sesion en el servidor utilizando la funcion session_destroy():

session_destroy();
Nota que la prioridad para utilizar cualquiera de estos metodos es siempre iniciar session_start(), para que los datos de sesion sean recogidos.

1.- abrimos el archivo logout.php
2.- agregamos al inicio del archivo session_start();
3.- Cambiamos la condicional en lugar de $_COOKIE usamos $_SESSION
4.- reemplazamos las lineas de setcookie() por $_SESSION = array(); session_destroy(); y eliminamos del mensaje de cerrado de sesion {$_COOKIE['first_name']}:


<?php

 // iniciamos sesion
 session_start();

 // esta pagina deja al usuario cerrar sesion
 // si la cookie no esta presente, redirige al usuario:

 if (!isset($_SESSION['user_id'])) {
  // necesitamos las funciones
  require('includes/login_functions.inc.php');
  redirect_user();
 }else{
  // Eliminamos las cookies:
  $_SESSION = array();
  session_destroy();
 }
 // Establecemos un titulo a la pagina
 $page_title = 'Cerrar sesion';
 include('includes/header.html');

 // Imprimimos un mensaje personalizado

 echo "<h1>Cierre de sesion!</h1>
 <p>Tu cesion ha sido cerrada correctamente</p>";

 include('includes/footer.html');
?>

Hasta aqui termina la septima parte de PHP, nos vemos en la proxima parte :).

lunes, 1 de septiembre de 2014

Resumen reCaptcha

¿Que es reCaptcha?


reCaptcha te ayuda a prevenir a que abusen de tu sitio (que metan spam o que registren cuentas falsas) el captcha asegura que un humano esta realizando la accion.

 

API Keys



Para obtener una clave es necesario registrar nuestro dominio:

https://www.google.com/recaptcha/admin#whyrecaptcha

Puedes poner 1 o mas dominios separarlos por comas, ejemplo:

http://www.arthusu.blogspot.com,http://www.tutorialesarthusu.comlu.com,http://www.most-security.com,http://www.underc0de.org
Por defecto todas las claves funcionan en "localhost" con la ip 127.0.0.1 para que puedas hacer pruebas en tu servidor local.

Integrarlo

Para poder integrar reCaptcha a tu sitio solo es necesario realizar los tres pasos siendo el tercero opcional:

1.- Del lado del cliente: mostrar el widget recaptcha (Requerido)
2.- Del lado del servidor: verificar la solucion (Requerido)
3.- Personalizar  (Opcional)

En la mayoria de los formularios webs tu usualmente tienes dos archivos: el formulario con los campos y el script que procesa los campos del formulario. Estos dos archivos corresponden al paso 1 y 2. Por lo tanto se tendran que modificar 2 archivos diferentes en la mayoria de los casos.

Hay dos maneras de agregar reCaptcha (a) con plugins o (b) sin plugins. Nosotros veremos la primera forma, que es con plugins utilizando PHP.


Usando reCaptcha en PHP

Para utilizar reCaptcha con PHP necesitas descargar la libreria:

https://code.google.com/p/recaptcha/downloads/list?q=label:phplib-Latest

De los archivos que vienen en el zip comprimido solo necesitas 1 archivo el que se llama recaptchalib.php los demas son ejemplos y cuestiones legales.

Despues de haberte registrado para poder usar la clave del API podemos proceder.

Del lado del cliente: como crear el captcha la imagen aparece


Si quieres utilizar la libreria reCaptcha de PHP para mostrar el widget, solo necesitas insertar la siguiente parte de codigo dentro de un elemento <form> donde el widget CAPTCHA sera colocado:


<?php
 require_once('recaptchalib.php');
 $clavepublica = "Aquivatuclavepublica"; // esta la obtienes cuando te registras
 echo recaptcha_get_html($clavepublica); 
?>

Con el codigo anterior tu formulario luciria como el siguiente:

<!DOCTYPE html>
<html>
<head>
 <title>reCaptcha</title>
</head>
<body>
<!-- El body es requerido ya que sino el captcha no se mostrara en algunos navegadores -->
<form method="post" action="verificar.php">
  <?php
   require_once('recaptchalib.php');
   $clavepublica = "Aquivatuclavepublica"; // esta la obtienes cuando te registras
   echo recaptcha_get_html($clavepublica); 
  ?>
 <input type="submit" />
</form>
</body>
</html>
 

No olvides reemplazar en la variable $clavepublica donde dice Aquivatuclavepublica por tu clave publica.

Si miras en el formulario se encuentra en el atributo action verificar.php este archivo es importante ya que aqui sera procesado el formulario, este archivo deberia de encontrarse en la misma localizacion que el archivo del formulario html.

Con la funcion require_once() llamamos al archivo requerido que es la libreria para el captcha, si este no se encuentra el script no puede continuar, recuerda colocar la ruta correctamente require_once(turuta/dondeseencuentra/recaptchalib.php)

Del lado del cliente: como probar que lo introducido por el usuario es lo correcto

El siguiente codigo deberia ser puesto al incio del archivo verificar.php:


<?php
 require_once('recaptchalib.php');
 $claveprivada = "Tuclaveprivada";
 $respuesta = recaptcha_check_answer($claveprivada,
     $_SERVER["REMOTE_ADDR"],
     $_POST["recaptcha_challenge_field"],
     $_POST["recaptcha_response_field"]);
 if (!$respuesta->is_valid) {
  // El captcha se metio incorrectamernte
  die("El captcha no se ingreso correctamente. Ve atras y vuelve a intentarlo". $respuesta->error);
 }else{
  // Tu codigo para manejar una verificacion correcta
  echo "Bien hecho";
 }
?>

En el codigo de arriba:

* recaptcha_check_answer - retorna un objeto representando cuando el reto se completo correctamente
* Si $respuesta->is_valid si es true entonces puede continuar con el procesamiento del formulario
* Si $respuesta->is_valid si es false entonces muestra de nuevo otra imagen en el captcha. En caso de que $respuesta->error ocurra un error el captcha mostrara el codigo de error.

Nota importante: No confundas la clave publica con la clave privada.

Estaté seguro de que hayas colocado el array superglobal $_POST para usar el captcha.

Hasta aqui llega nuestro pequeño resumen de reCaptcha si quieres obtener mas informacion puedes consultar: https://developers.google.com/recaptcha/docs/php


 

sábado, 30 de agosto de 2014

[Parte 6] PHP

Buenas tengo ya bastante tiempo sin escribir en el blog y es por que me he quedado sin pc, estare escribiendo desde un ciber pero intentare actualizar este par de entradas, iva comenzar con como hacer una paginacion pero eso es algo que ya vimos en el blog, por lo cual solo les dejare un enlace y veremos otras cosas :)

Enlace para crear una paginacion:

http://arthusu.blogspot.mx/2013/09/sistema-de-paginacion-en-php-y-mysql.html


Enviar un correo

Con php podemos enviar correos a otras personas con solo usar la funcion mail(). Su sintaxis es la siguiente:

mail(para,asunto,cuerpo,[cabeceras])

expliquemos cada una de estas opciones:

para: es para quien va dirigido ahi va el correo a quien va dirigido. Por ejemplo: falso@hotmail.com y si quisieramos agregar mas de una simplemente tendriamos que agregar una coma y otro correo, de la siguiente manera: falso@hotmail.com,falso2@hotmail.com

asunto: es el asunto del mensaje que estas escribiendo, esto se refiere al titulo que va a ver la persona en el mensaje que le estas enviando, de esta manera muchas veces eligen si lo abren o no.

cuerpo: es el mensaje dirigido a la persona. Usando \n podemos hacer un salto de linea.

cabeceras: este esta encerrado entre corchetes por que es opcional con lo cual no es necesario escribirlo pero nos da unas cuantas opciones al usarlo.

Nota importante: para poder usar esta funcion mail() debe tener un servidor de correos corriendo. Si no cuenta con uno puede usar un servdor gratuito como lo es 000webhost. Un ejemplo:



En este caso el script php es algo simple, se podrian agregar mas cosas pero entre mas simple sea mas entendible es :P.

Con este script php que acabamos de hacer facilmente podriamos implementarlo en una parte de la pagina para que alguien te contacte en caso de que asi lo quieras agregando un antispam... como podria ser un captcha por ejemplo.



Subir archivos


El proceso de subir archivos tiene dos dimensiones. Primero el codigo HTML es mostrado y despues el codigo apropiado para subir archivos. El archivo subido mediante el formulario es subido a un directorio temporal del cual despues es movido a la carpeta final. Para que este proceso trabaje correctamente es necesario tener algunas configuraciones:

- PHP debe tener las configuraciones correctas
- El directorio temporal debe existir con los permisos adecuados (775 o 777)
- Donde se almacenara el archivo final debe existir con los permisos adecuados

Configuraciones de subidas de archivos:




Para usuarios de Mac Os X y Unix existe ya una carpeta temporal llamada /tmp. Y en windows la configuracion por defecto tiene el valor vacio,si estas usando XAMPP no es necesario modificar estos valores.

Como las carpetas que subes a internet son publicas lo que se puede hacer en esos casos es poner un archivo de configuracion .htaccess para que el publico no pueda acceder a esa carpeta y ver todo lo que esta dentro. O tambien puedes poner la carpeta al mismo nivel de el directorio publico.

Con phpinfo() usted puede ver la configuracion de php con lo cual puede ver como se encuentra configurado para la subida de archivos.



Si estas utilizando linux que es lo que la mayoria de los servidores tienen puedes usar el comando chmod para cambiar los permisos a tus carpetas o archivos y darle los permisos 775 o 777

Si subes un archivo pesado este puede tardar mucho tiempo en subirse, por lo cual puedes especificar en la directiva max_input_time el tiempo que quieres que dure un archivo o simplemente utilizar la funcion set_time_limit(). Entre los parentesis debe ir los segundos en tiempo.


Para subir un archivo es necesario de 2 partes: HTML y PHP.



El enctype al principio del formulario indica que va ser capaz de manejar muchos tipos de datos incluyendo los archivos. Tambien debes notar que el método debe ser POST.

El campo de entrada oculto (hidden) MAX_FILE_SIZE indica el maximo de largo del archivo (en bytes), es una restriccion facil que puede ser usada.

El archivo puede ser accedido usando el array superglobal $_FILES. Incluso si el archivo es recibido por el script PHP puede ser transferido de un directorio temporal a uno permanente usando la funcion move_uploaded_file().


move_uploaded_file(archivo_temporal,/ruta/a/mover/archivo);

Valores del array superglobal $_FILES:



Índice
Significado
Name
El nombre original del archivo
Type
El tipo MIME del archivo es dado por el navegador
Size
El tamaño subido del archivo es dado en bytes
Tmp_name
El nombre temporal del archivo almacenado en el servidor
Error
Codigo de error asociado con el problema

Veamos como crear un script en el cual se suba un archivo a la carpeta upload/ y verifique que el tipo de archivo sea una imagen PNG o JPG...


<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8" />
 <title>Sube una imagen</title>
 <style type="text/css">
  .error{
   font-weight: bold;
   color: #c00;
  }
 </style>
</head>
<body>
<form enctype="multipart/form-data" action="" method="post">
 <input type="hidden" name="MAX_FILE_SIZE" value="3000000" />
 Archivo <input type="file" name="upload" />
 <input type="submit" name="enviar" />
</form>
<?php
 if($_SERVER['REQUEST_METHOD'] == 'POST'){
  if(isset($_FILES['upload'])){
   $permitidos = array('image/pjpeg','image/jpeg','image/JPG','image/X-PNG','image/PNG','image/png','image/x-png');
   if(in_array($_FILES['upload']['type'], $permitidos)){
    if(move_uploaded_file($_FILES['upload']['tmp_name'], "../uploads/{$_FILES['upload']['name']}")){
     echo '<p><em>El archivo ha sido subido!</em></p>';
    }
   }else{
    echo '<p class="error">Por favor suba una imagen en formato JPEG o PNG.</p>';
    print_r($_FILES['upload']);
   }
  }
 }
?>
</body>
</html>

Con esto lo que hace $_SERVER['REQUEST_METHOD'] == 'post' si es el metodo enviado esta por POST que siga con el script, si existe el array UPLOAD entonces seguimos con el script... Aqui viene una de las partes mas importantes que es los archivos que se permiten y se verifica por su mime type, creamos un array llamado $permitidos con el tipo de archivos que se permiten... luego si se encuentra el archivo que vamos a subir entre el array entonces intentamos mover el archivo si se pudo mover el mensaje de que el archivo se ha subido se mostrara, sino lo mas posible es que muestre un mensaje de error por los permisos. Si no tenemos el archivo dentro de nuestro array nos podria mostrar un mensaje de error que suba el tipo de archivo que se requiere. 


Nota: Este tipo de Upload no es seguro ya que todas las cabeceras pueden ser modificadas...

Tambien podriamos agregar al script el tipo de error que es por lo cual el archivo no se pudo subir, uno del mas comun podria ser la restriccion HTML del maximo de peso permitido.
Otra cosa que ocurre comunmente es que si el archivo existe se desea eliminar... aunque si estuvieramos creando un servidor de imagenes lo ideal seria poner un nombre unico randomizado de manera que si alguna persona sube su archivo se encuentre tal y como debe ser.


<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8" />
 <title>Sube una imagen</title>
 <style type="text/css">
  .error{
   font-weight: bold;
   color: #c00;
  }
 </style>
</head>
<body>
<form enctype="multipart/form-data" action="" method="post">
 <input type="hidden" name="MAX_FILE_SIZE" value="3000000" />
 Archivo <input type="file" name="upload" />
 <input type="submit" name="enviar" />
</form>
<?php
 if($_SERVER['REQUEST_METHOD'] == 'POST'){
  if(isset($_FILES['upload'])){
   $permitidos = array('image/pjpeg','image/jpeg','image/JPG','image/X-PNG','image/PNG','image/png','image/x-png');
   if(in_array($_FILES['upload']['type'], $permitidos)){
    if(move_uploaded_file($_FILES['upload']['tmp_name'], "../uploads/{$_FILES['upload']['name']}")){
     echo '<p><em>El archivo ha sido subido!</em></p>';
    }
   }else{
    echo '<p class="error">Por favor suba una imagen en formato JPEG o PNG.</p>';
   }
  }
  if($_FILES['upload']['error'] > 0){
   echo '<p class="error">El archivo no se pudo subir por que: <strong>';
   switch ($_FILES['upload']['error']) {
    case 1:
     print 'El archivo excedio el maximo de la directiva upload_max_filesize en php.ini';
     break;
    case 2:
     print 'El archivo excedio el maximo de peso en MAX_FILE_SIZE del formulario HTML';
     break;
    case 3:
     print 'El archivo fue subido solo parcialmente';
     break;
    case 4:
     print 'Ningun archivo fue subido';
     break;
    case 6:
     print 'La carpeta temporal no esta disponible';
     break;
    case 7:
     print 'No se pudo escribir el archivo en el disco';
     break;
    case 8:
     print 'La subida del archivo fue detenida';
     break;
    default:
     print 'Ha ocurrido un error en el sistema';
     break;
   }
   print '</strong></p>';

   //Elimina el archivo si existe:
   if(file_exists($_FILES['upload']['tmp_name']) && is_file($_FILES['upload']['tmp_name'])){
    unlink($_FILES['upload']['tmp_name']);
   }
  }
 }
?>
</body>
</html>


Explicando un poco lo nuevo que se le agrego al script, es un switch el cual evalua que el codigo del error si es diferente a 0 (El archivo se subio con exito) muestra un mensaje para cada tipo de error. Y la otra parte del codigo lo unico que hacemos es ver si el archivo temporal ya existe de manera que lo elimine para asi poder subir el nuevo.

Nota: Tambien se puede verificar si el archivo se subio, usando la funcion is_uploaded_file().


Usar PHP y Javascript Juntos

Podemos usar PHP con Javascript, la diferencia entre los dos es que Javascript es del lado del cliente y PHP del lado del servidor, tenemos muchas ventajas en cuanto a los dos, ya que con javascript podemos manejar mucho el navegador, ya sea el tamaño de una ventana, obtener algun objeto, etc. Y con PHP podemos manejar muchas funciones entre ellas interactuar con la base de datos, y en conjunto los dos puede ser una buena combinacion.

En este caso vamos a crear un script con el cual mostraremos una lista de todos los archivos subidos utilizando javascript y PHP juntos.


Creando un archivo Javascript

Como cuando iniciamos un codigo PHP tenemos etiquetas de apertura para ello, o un HTML, al igual tenemos con Javascript. Para saber que ahi esta su codigo. Podemos crear codigo javascript dentro del mismo archivo o externamente:

Dentro del mismo archivo:



<script type="text/javascript">
 //El codigo va aqui dentro
</script>


En un archivo externo:


<script type="text/javascript" src="archivo.js"></script>

En el caso del archivo externo tendriamos que crear archivo.js y dentro del el codigo javascript.




Una caracteristica que diferencia Javascript de php es que sus variables no van declaradas con el signo dolar. Javascript tambien es orientado a objetos y podemos acceder a ellos usando el punto (.), seria algo como: algo.algo o algo.algo.algo().


Vamos a crear nuestro javascript, para crear una ventana emergente de nuestra imagen cuando le demos click a los enlaces de el listado de archivos:


function.js


function crear_ventana(imagen,ancho,alto){
 ancho = ancho + 10;
 alto = alto + 10;

 if (window.popup && !window.popup.closed) {
  window.popup.resizeTo(ancho,alto);
 }

 var specs = "location=no, scrollbars=no, menubars=no, toolbars=no, resizable=yes, left=0, top=0, width="+ ancho +", height="+alto;

 var url = "mostrar_imagen.php?imagen="+imagen;

 popup = window.open(url,"ImageWindow",specs);
 popup.focus();
}


1.- Creamos la funcion crear_ventana(imagen,ancho,alto) con sus parametros

2.- despues agrega las variables ancho y alto y le da 10 pixeles mas (para que la imagen sea mas grande cuando se abra), como habiamos comentado anteriormente en javascript las variables no llevan el signo dolar.

3.- luego verificamos si la ventana ya existe y si no esta cerrada, lo que hacemos es motrar en esa misma ventana la nueva imagen. Como puedes darte cuenta tambien estamos utilizando POO (programacion orientada a objetos) en javascript, ya que utilizamos varias funciones como lo es resizeTo()

4.- La variable specs especificamos los parametros para la ventana que vamos abrir al momento de darle clic al enlace, de las mas importantes que nos deje que se modifique el tamaño de la ventana, que la url no se pueda modificar, que no se muestren las barras de scroll ni el menu de herramientas, que se acomode en la esquina izquierda y que tenga un tamaño con las variables que habiamos declarado anteriormente.

5.- la variable url, sera a la url a la que entrará modificando siempre la imagen segun la indique en el archivo php (este se mostrara mas adelante).

6.- Por ultimo creamos la funcion con la cual nuestra imagen sera abierta en la ventana nueva, en la cual especificamos la url, el titulo de la ventana, y los parametros dados anteriormente en una variable, al final le damos el foco para que se quede en la ventana que abriremos.

Creando el archivo PHP

Bueno como todos sabemos en PHP se puede embeber codigo javascript al igual que HTML, crearemos nuestro archivo PHP recorriendo todas las imagenes que se han subido al servidor para de esta manera crear nuestra lista y pasar los parametros correctos por la funcion crear_ventana(imagen,ancho,alto).

Imagenes.php





<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8" />
 <title>Imagenes</title>
 <script type="text/javascript" src="funcion.js"></script>
</head>
<body>
 <p>Da click en la imagen para verla en una ventana separada.</p>
 <ul>
  <?php
   $dir = '../uploads';
   $files = scandir($dir);

   foreach($files as $image){
    if(substr($image,0,1) != '.'){
     $image_size = getimagesize("$dir/$image");
     $image_name = urlencode($image);

     echo "<li>
      <a href=\"javascript:crear_ventana('$image_name',$image_size[0],$image_size[1])\">$image</a>
           </li>\n";
    }
   } 
  ?>
 </ul>
</body>
</html>

Vamos a explicar todo esto para que se entienda.

1.- Incluimos el archivo function.js el cual es el codigo anterior de javascript el que crea la ventana emergente.

2.- Creamos una lista desordenada, y luego especificamos la variable $dir la cual contiene el nombre de nuestro directorio de imagenes (el que usamos en el upload), con la funcion scandir($dir) escaneamos el directorio el cual especificamos el cual se convierte en una array $files con el nombre de todos nuestros archivos.

3.- En esta parte utilizamos un foreach para recorrer cada elemento del array convirtiendolo en una variable, de manera que para cada $files archivo hay una $image imagen, despues verificamos que si el nombre de la imagen en el recorrido no empieza con un . (punto) que siga con el script, esto es por que no seria una imagen, ademas de que .. (dos puntos) es un directorio atras.

4.- Con la funcion getimagesize() obtenemos mucha informacion sobre la imagen:



Los cuales tienen el siguiente significado:

0 => tamaño en ancho px
1 => tamaño en alto px
2 => tipo de imagen 2 (en este caso jpeg)
3 => atributos de ancho y alto para la etiqueta img
mime => el tipo de imagen

Despues de eso al nombre de la imagen le pasamos la funcion urlencode() esto es por si contiene un caracter extraño en cual no es permitido en la url, pues con esta funcion lo codificamos de manera que se pueda interpretar en la url.
 
5.- Por ultimo creamos una lista de enlaces el cual utiliza la funcion de javascript que creamos anteriormente pasandole algunos parametros como son el nombre de la imagen, el ancho y alto que tomamos del PHP con la funcion getimagesize().

Ahora mismo si probamos el script se muestra nuestra lista, pero al darle clic no se muestra la imagen ya que el archivo mostrar_imagen.php todavia no lo hemos creado.


Comprendiendo las cabeceras

Como vimos anteriormente habiamos guardado las imagenes fuera del directorio root de manera que los usuarios que visiten nuestra pagina no podran acceder de manera publica a las rutas de la imagen, lo cual es mas seguro.

Lo que vamos a crear en si seria un tipo de "proxy de imagenes" en PHP, a lo cual nosotros pasaremos el nombre de la imagen y no las mostrara, le llamo "proxy" por que las imagenes pasan atraves de ese script, pero en realidad el usuario visitante no sabe donde estan, lo cual es bueno :D.



HTTP (Hypertext Transfer Protocol) como ya hemos explicado ya varias veces en este blog es un protocolo que sirve para comunicarse el cliente con el servidor. El navegador recibe algunos headers HTTP (cabeceras) que pasan de manera oculta (en segundo plano). 

PHP creo una funcion llamada header() para tomar ventaja de este protocolo. El ejemplo mas basico y comun para lo que se utiliza esta funcion es para redirigir de una pagina a otra. En este caso la utilizaremos para enviar un archivo al navegador.

Esta funcion es realmente facil de usar, su sintaxis es:

header(cabecera string)

La lista de posibles cabeceras son muchas, pero las mas usadas son las que utilizan para redirigir, enviar archivos al navegador, crear cookies, controlar el cache y mucho mas. Vamos a crear un ejemplo simple:


header('Location: https://www.google.com');

Con eso nosotros redirigimos a la pagina de google.

En el siguiente ejemplo enviaremos una imagen al navegador, para ello seran usadas tres cabeceras:

1.- Content-Type esta cabecera indica el tipo de datos que sera enviado, muchos valores coinciden con el mime type. Un ejemplo podria ser el de un archivo PDF: 

header("Content-Type: application/pdf\n");

2.- Content-Disposition con esto le decimos al navegador que lo siguiente sea tratado como datos.

header("Content-Disposition: attachment; filename="\algunarchivo.pdf\"\n"); 

Con el valor attachment muestra una ventana de descarga.

3.- Content-Length  este valor contiene la cantidad o tamaño de datos que se estan enviando.

header("Content-Length: 4096\n");

Vemos hay algunas cosas importantes al utilizar las cabeceras, una de ellas es que usamos \n para dividir una nueva linea con lo cual creamos una cabecera y debemos terminar con una nueva linea para ir con la cabecera. Otra cosa importante es que la funcion header() debe ser llamada antes que cualquier cosa ya sea HTML o un espacio en blanco, ya que sino mostrara un error:



Vamos a crear el script para mostrar las imagenes y explicarlo.

mostrar_imagen.php


<?php
 $name = FALSE; // variable para la cabecera
 // checar en nombre de la imagen en la url
 if (isset($_GET['imagen'])) {
  // asegurarse de la extension sea de imagen
  $ext = strtolower(substr($_GET['imagen'], -4));

  if (($ext == '.jpg') OR ($ext == '.jpeg') OR ($ext == '.png')) {
   // ruta completa de la imagen
   $image = "../uploads/{$_GET['imagen']}";

   // checar si la imagen existe y es un archivo
   if (file_exists($image) && is_file($image)) {

    // establecemos el nombre de la imagen
    $name = $_GET['imagen'];
   }
  }
 }
 // si ocurre un problema mostramos una imagen por defecto
 if (!$name) {
  $image = 'images/unavailable.png';
  $name = 'unavailable.png';
 }
 // obtenemos informacion sobre la imagen
 $info = getimagesize($image);
 $fs = filesize($image);
 // enviamos la informacion
 header("Content-Type: {$info['mime']}\n");
 header("Content-Disposition: inline; filename=\"$name\"\n");
 header("Content-Length: $fs\n");
 // enviamos el archivo
 readfile($image);
?>

1.- Creamos la variable $name la cual sera leida como validacion si la imagen existe en realidad, recuerda que como estamos usando header no debe haber ningun espacio al abrir las etiquetas de php.

2.- Checamos si existe la variable imagen

3.- Creamos una variable llamada $ext que agarra los ultimos cuatro caracteres de la imagen y luego validamos si coincide con imagenes tipo jpeg o png, y si es asi creamos una variable llamada imagen la cual contiene la ruta completa.

4.- Despues de eso verificamos que la imagen exista y que sea un archivo, si es asi, establecemos su nombre en la variable $name la cual estaba en falso por defecto ya veras mas adelante el por qué.

5.- Si $name es falso entonces mostramos una imagen por defecto.



6.- Obtenemos informacion sobre la imagen con getimagesize().

7.- Enviamos la informacion, una cosa es que en la cabecera Content-Disposition utilizamos inline que sirve para mostrar los datos en el navegador.

8.- Por ultimo con readfile() leemos los datos enviados de manera que se puedan mostrar correctamente en el navegador.



Algunas cosas utiles sobre cabeceras son:

* Podemos evitar problemas al enviar cabeceras utilizando la funcion headers_sent() de esta manera podemos crear algo como lo siguiente:


if(!headers_sent()){ usar la funcion header()}else{ // hace otra cosa}
* Podemos utilizar el encoding UTF-8 para que acepte mas caracteres utilizando la funcion header():


header('Content-Type: text/html; charset=UTF-8');

Podemos debuggear las cabeceras utilizando un sin fin de herramientas como son Web Developer Toolbar, Live Http Headers, Tamper Data, o simplemente con el inspeccionador de firefox o chrome:





Funciones de tiempo y fecha

Comenzaremos primero con que la hora para cada parte de la ciudad es diferente, hay una funcion llamada date_default_timezone_set() la cual establece una zona horaria predeterminada. Aqui hay una lista: http://php.net/manual/es/timezones.php esta configuracion tambien puede ser modificado desde el php.ini. Veamos un ejemplo:


date_default_timezone_get("America/Chihuahua");
Tambien esta la funcion checkdate(mes,dia,año) que comprueba la validez de una fecha formada por los argumentos. Devuelve TRUE si la fecha dada es valida sino devuelve FALSE.

La funcion date() da formato a la fecha/hora local. Su sintaxis ers la siguiente:
string date ( string $format [, int $timestamp = time() ] )
Los siguientes caracteres están reconocidos en el parámetro de cadena format
Carácter de format Descripción Ejemplo de valores devueltos
Día --- ---
d Día del mes, 2 dígitos con ceros iniciales 01 a 31
D Una representación textual de un día, tres letras Mon hasta Sun
j Día del mes sin ceros iniciales 1 a 31
l ('L' minúscula) Una representación textual completa del día de la semana Sunday hasta Saturday
N Representación numérica ISO-8601 del día de la semana (añadido en PHP 5.1.0) 1 (para lunes) hasta 7 (para domingo)
S Sufijo ordinal inglés para el día del mes, 2 caracteres st, nd, rd o th. Funciona bien con j
w Representación numérica del día de la semana 0 (para domingo) hasta 6 (para sábado)
z El día del año (comenzando por 0) 0 hasta 365
Semana --- ---
W Número de la semana del año ISO-8601, las semanas comienzan en lunes (añadido en PHP 4.1.0) Ejemplo: 42 (la 42ª semana del año)
Mes --- ---
F Una representación textual completa de un mes, como January o March January hasta December
m Representación numérica de una mes, con ceros iniciales 01 hasta 12
M Una representación textual corta de un mes, tres letras Jan hasta Dec
n Representación numérica de un mes, sin ceros iniciales 1 hasta 12
t Número de días del mes dado 28 hasta 31
Año --- ---
L Si es un año bisiesto 1 si es bisiesto, 0 si no.
o Número de año ISO-8601. Esto tiene el mismo valor que Y, excepto que si el número de la semana ISO (W) pertenece al año anterior o siguiente, se usa ese año en su lugar. (añadido en PHP 5.1.0) Ejemplos: 1999 o 2003
Y Una representación numérica completa de un año, 4 dígitos Ejemplos: 1999 o 2003
y Una representación de dos dígitos de un año Ejemplos: 99 o 03
Hora --- ---
a Ante meridiem y Post meridiem en minúsculas am o pm
A Ante meridiem y Post meridiem en mayúsculas AM o PM
B Hora Internet 000 hasta 999
g Formato de 12 horas de una hora sin ceros iniciales 1 hasta 12
G Formato de 24 horas de una hora sin ceros iniciales 0 hasta 23
h Formato de 12 horas de una hora con ceros iniciales 01 hasta 12
H Formato de 24 horas de una hora con ceros iniciales 00 hasta 23
i Minutos, con ceros iniciales 00 hasta 59
s Segundos, con ceros iniciales 00 hasta 59
u Microsegundos (añadido en PHP 5.2.2). Observe que date() siempre generará 000000 ya que toma un parámetro de tipo integer, mientras que DateTime::format() admite microsegundos. Ejemplo: 654321
Zona Horaria --- ---
e Identificador de zona horaria (añadido en PHP 5.1.0) Ejemplos: UTC, GMT, Atlantic/Azores
I (i mayúscula) Si la fecha está en horario de verano o no 1 si está en horario de verano, 0 si no.
O Diferencia de la hora de Greenwich (GMT) en horas Ejemplo: +0200
P Diferencia con la hora de Greenwich (GMT) con dos puntos entre horas y minutos (añadido en PHP 5.1.3) Ejemplo: +02:00
T Abreviatura de la zona horaria Ejemplos: EST, MDT ...
Z Índice de la zona horaria en segundos. El índice para zonas horarias al oeste de UTC siempre es negativo, y para aquellas al este de UTC es siempre positivo. -43200 hasta 50400
Fecha/Hora Completa --- ---
c Fecha ISO 8601 (añadido en PHP 5) 2004-02-12T15:19:21+00:00
r Fecha con formato » RFC 2822 Ejemplo: Thu, 21 Dec 2000 16:01:07 +0200
U Segundos desde la Época Unix (1 de Enero del 1970 00:00:00 GMT) Vea también time()

Esta tabla fue tomada del manual oficial de php.

Veamos algunos ejemplos utilizando la funcion date():


echo date('F j, Y'); // August 30, 2014 
echo date('H:i'); // 18:12
echo date('D'); // Sat
Los resultados que arrojaran estan como comentarios, tambien si te das cuenta esos estan en ingles y podrian ser modificados usando un array con nombres en español y un switch como condicional para los nombres.

mktime() obtiene la marca de tiempo Unix de una fecha. Su sintaxis:

int mktime ([ int $hour = date("H") [, int $minute = date("i") [, int $second = date("s") [, int $month = date("n") [, int $day = date("j") [, int $year = date("Y") [, int $is_dst = -1 ]]]]]]] )
Esto es lo mismo que si usamos la funcion time(), solo que aqui podemos asignar los parametros que nos convengan.

Por ultimo tenemos getdate() la cual retorna un array de valores de fecha y hora.

Array
(
    [seconds] => 34
    [minutes] => 22
    [hours] => 18
    [mday] => 30
    [wday] => 6
    [mon] => 8
    [year] => 2014
    [yday] => 241
    [weekday] => Saturday
    [month] => August
    [0] => 1409444554
)

Vamos a modificar nuestro script imagenes.php para agregarle a la lista de archivos la fecha/hora y peso del archivo.



<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8" />
 <title>Imagenes</title>
 <script type="text/javascript" src="funcion.js"></script>
</head>
<body>
 <p>Da click en la imagen para verla en una ventana separada.</p>
 <ul>
  <?php
   //establecemos el timezone por defecto
   date_default_timezone_get("America/Chihuahua");

   $dir = '../uploads';
   $files = scandir($dir);

   foreach($files as $image){
    if(substr($image,0,1) != '.'){
     $image_size = getimagesize("$dir/$image");

     // calculamos el tamaño de la imagen en kilobytes
     $file_size = round(filesize("$dir/$image"),1024) . " kb";

     //determinamos la fecha y hora en que se subio la imagen
     $image_date = date("F d, Y H:i:s",filemtime("$dir/$image"));

     $image_name = urlencode($image);

     echo "<li>
      <a href=\"javascript:crear_ventana('$image_name',$image_size[0],$image_size[1])\">$image</a> $file_size ($image_date)
           </li>\n";
    }
   } 
  ?>
 </ul>
</body>
</html>



Las lineas subrayadas son las lineas nuevas, vamos a explicarlas.


1.- Establecemos la zona horaria por defecto como America/Chihuahua

2.- Obtenemos el tamaño en kb para ello hacemos uso de round para redondear y como el tamaño es en bytes lo dividimos entre 1024 para que sea en kilobytes, con filesize() obtenemos el tamaño en bytes.

3.- Obtenemos la fecha de modificacion de cada archivo, para ello hacemos uso de la funcion filemtime() y con la funcion date() mostramos la fecha y hora formateada.

5.- Agregamos en la linea donde imprimos el enlace aun lado el tamaño y la fecha del archivo.

Algunas cosas utiles sobre fecha y hora:

* Las funciones de fecha y hora estan reflejadas en el tiempo y hora del servidor si quieres que sea la misma para cada parte del pais es mejor utilizar javascript para usar la hora que tiene configurada el cliente del navegador.

Bueno hasta aqui la parte 6 de PHP, espero poder seguir la 7 pronto ya que me atrase mucho tiempo en el BLOG saludos :D.