Registro de usuarios desde cero.

El tuto 7 creo que el archivo es inseguro; te pueden pasar un para con mala intención y robarte incluso la pagina hay que mejorar ese codigo.

Si si, el muy inseguro. Repito que el objetivo es entender primero cómo funciona y, ahora, ir mejorándolo para evitar problemas de seguridad, añadir nuevas funcionalidades, etc, etc.

Hay que verificar cada dato recogido en los formularios para evitar las inyecciones, etc, etc, etc. Forma parte de las siguientes partes del tutorial, no lo dudes.

Gracias de nuevo!
Añado un mensaje de advertencia al principio del tuto, para evitar que la gente lo use antes de terminar la parte de la seguridad de esta aplicación.
Imagino, pero no se a qué te refieres exáctamente ni como evitar que esos archivos entren el el sitemap o sean leidas por los robots de buscadores solo por incluirlas en las url. Imagino que con las líneas apropiadas en el .htaccess solvento la papeleta igualmente, pero dinos tu propuesta que somos todo oidos y sabemos apreciar los buenos consejos!
En el mensaje inicial iré escribiendo un listado con las tareas por hacer, para acordarme de lo que falta por añadir y, por si alguien se anima.
Bueno la propuesta en resumen es en vez de llamar a las url´s me parece mejor definir contantes que incluyan o requieran los archivos a los que haces mención y hacer una llamada a la constante en vez de a la url, por otro lado para no marear mucho al usuario lo ideal seria que el login estuviese embebido en una pagina de inicio y que sin necesidad de salir de ella se pueda ver y rellenar y validar nuestro formulario.y por lo tanto logarnos. Se me acurre incluso que para avisar al usuario de que se ha logado bien le podemos pasar un alert () de javascript en formato standar u otros para darle la notificación . Como ves lo que planteo es algo más complejo de lo que planteas pero como se que no es complicado; pues te lo digo por eso.
Puedes ponernos algún ejemplo de ese uso de constantes? Me da que no es lo que yo entendía como tales.

Lo de embeber el registro en las páginas de la web es una de mis ideas, claro. Requiere creo el uso de AJAX para evitar la recarga de las páginas y tal y aún ando haciendo pruebas antes de poder explicarlo.

La idea es ir poco a poco, entendiendo sobre todo cada paso que demos, para poder meter mano al codigo si queremos retocar algo sabiendo dónde tocar.

Una de mis pruebas es esta, bastante completita, aunque me falla en algunos navegadores. No es mio, es solo retocado de alguno ya hecho.

www.gruposbandasysalasdeconciertos.com/demo02.php
Basicamente lo que te decia antes es que usando las constantes (algo asi como variables globales); podemos llamar a esa variables (una vez definidas,claro), para que pasen el archivo en vez de llamar al archivo directamente asi no se indexaria la url y como la historia es que la transferencia de datos sea rapida luego podemos usar esa contante para carga uno o otro archivo via ajax
[TUTORIAL :: SISTEMA DE REGISTRO DE USUARIOS :: PARTE 11]

Tenemos un problema con lo visto hasta ahora. Cualquier persona podría registrarse con un nick ya existente en nuestra base de datos. Eso sería un problema, no? Para evitarlo, hemos de comprobar, antes de enviar los datos del formulario a la base de datos, que no existe ya un usuario con ese mismo nick.

Nombre del archivo: registro.php

<?php

include('configuracion.php');

//Comprobamos que los campos nick y password no están en blanco
if(($_POST[nick] == '') or ($_POST[password] == '') )
   {
Header("Location: formulario.php"); // si están en blanco enviarmos al registro de nuevo
   }
else
   {
   // cuántos usuarios hay ya con ese nick?
   $cuantosnicks=mysql_query("SELECT nick FROM $tabla WHERE nick='$_POST[nick]' ");
   if ($nickrepetido=mysql_fetch_array($cuantosnicks))  // si existe ya algún nick idéntico...
        {
        echo 'El nick propuesto ya estaba registrado. Escoge otro.';
        echo '<br /><a href="formulario.php">Quieres intentarlo con otro nick?</a>'; // damos la opcion de registrarse de nuevo
        }
    else   // si no existe aún ese nick...
        {
        //introducimos el nuevo registro en la tabla users
        mysql_query("INSERT INTO $tabla (nick,password,email) values ('$_POST[nick]','$_POST[password]','$_POST[email]') ");
        echo 'Usuario registrado con éxito';
        echo '<br /><a href="login.php">Quieres logearte?</a>'; // damos la opcion de logerase
        }
   mysql_free_result($cuantosnicks);  //liberamos memoria
   }
?> 

Como veis, hacemos una consulta a la tabla preguntando cuántos usuarios hay con un nick como el del visitante que quiere registrarse. Si existe alguno se indica al visitante que escoja otro. Si no hay ninguno, se registra tal y como hacía la versión anterior.
[TUTORIAL :: SISTEMA DE REGISTRO DE USUARIOS :: PARTE 12]

Es posible que además, no queramos que un visitante registre dos cuentas con nicks distintos. Podemos conseguir evitar eso si vigilamos que no se puedan registrar dos nicks con el mismo email. Para ello hariamos como en el caso anterior, buscar si ya existe ese email, quedándo el archivo del siguiente modo:

Nombre del archivo: registro.php

<?php

include('configuracion.php');

//Comprobamos que los campos nick y password no están en blanco
if(($_POST[nick] == '') or ($_POST[password] == '') )
    {
Header("Location: formulario.php"); // si están en blanco enviarmos al registro de nuevo
    }
else
    {
    //cuantos usuarios hay ya con ese nick?
    $cuantosnicks=mysql_query("SELECT nick FROM $tabla WHERE nick='$_POST[nick]' ");
    //cuantos usuarios hay ya con ese email?
    $cuantosemails=mysql_query("SELECT email FROM $tabla WHERE email='$_POST[email]' ");
    if($nickrepetido=mysql_fetch_array($cuantosnicks))
        {
        echo 'El nick propuesto ya estaba registrado. Escoge otro.';
        echo '<br /><a href="formulario.php">Quieres intentarlo con otro nick?</a>'; // damos la opcion de registrarse de nuevo
        }
    else if($emailrepetido=mysql_fetch_array($cuantosemails))
        {
        echo 'El email propuesto ya estaba registrado. Escoge otro.';
        echo '<br /><a href="formulario.php">Quieres intentarlo con otro email?</a>'; // damos la opcion de registrarse de nuevo
        }
    else
        {
        //introducimos el nuevo registro en la tabla users
        mysql_query("INSERT INTO $tabla (nick,password,email) values ('$_POST[nick]','$_POST[password]','$_POST[email]') ");
        echo 'Usuario registrado con éxito';
        echo '<br /><a href="login.php">Quieres logearte?</a>'; // damos la opcion de logerase
        }
        mysql_free_result($cuantosnicks);  //liberamos memoria
        mysql_free_result($cuantosemails); //liberamos memoria
    }
?> 

Básicamente, hemos repetido lo anterior, no más.
Lantiga, me temo entonces que mis conocimientos no llegan para tanto. Si me puedes ayudar a aprender todos te lo agradecermos. En cualquier caso, sigo mejorando el registro con el que he empezado para ir aplicándo todo lo que aprendo sobre ellos y que el resto pueda nutrirse de él. Si consigo aprender lo que me comentas, sin duda lo aplicaré en el mismo para provecho de todos. Pero no sabría por dónde empezar ahora mismo. Empiezo por...?

Gracias una vez más!
Muy bien , pero tienes cosillas que ese te van de las manos, hechando un vistazo por encima hay varias instrucciones a corregir , por ejemplo en este ultimo codigo lo dejaria asi :

Nombre del archivo: registro.php

<?php

include_once('configuracion.php');

//Comprobamos que los campos nick y password no están en blanco
if(($_POST["nick"] == ' ') or ($_POST["password"] == ' ') )
    {
Header("Location: formulario.php"); // si están en blanco enviarmos al registro de nuevo
    }
else
    {
      
    //cuantos usuarios hay ya con ese nick?
    $cuantosnicks=mysql_query("SELECT nick FROM ".$tabla." WHERE nick='".$_POST["nick"]."' ");
    //cuantos usuarios hay ya con ese email?
    $cuantosemails=mysql_query("SELECT email FROM ".$tabla." WHERE email='".$_POST["email"]."' ");
      $nickrepetido = mysql_num_rows($cuantosnicks);
       $emailrepetido = mysql_num_rows($cuantosemails);
    if($nickrepetido >= 1)
        {
        echo 'El nick propuesto ya estaba registrado. Escoge otro.';
        echo '<br /><a href="formulario.php">Quieres intentarlo con otro nick?</a>'; // damos la opcion de registrarse de nuevo
        }
    else if($emailrepetido >= 1)
        {
        echo 'El email propuesto ya estaba registrado. Escoge otro.';
        echo '<br /><a href="formulario.php">Quieres intentarlo con otro email?</a>'; // damos la opcion de registrarse de nuevo
        }
    else
        {
        //introducimos el nuevo registro en la tabla users
        mysql_query("INSERT INTO $tabla (nick,password,email) values ('$_POST[nick]','$_POST[password]','$_POST[email]') ");
        echo 'Usuario registrado con éxito';
        echo '<br /><a href="login.php">Quieres logearte?</a>'; // damos la opcion de logerase
        }
        mysql_free_result($cuantosnicks);  //liberamos memoria
        mysql_free_result($cuantosemails); //liberamos memoria
    }
?> 

Aparentemente lo demas esta bien . al igual eres el primero que veo usando mayusculas en el query de mysql muy buena esa parte,
En cuanto a las constantes que decia lantiga son asi : define("NOMBRE DE CONSTANTE", "VALOR");

y la llamas simplemente con poner su nombre:

echo NOMBRE_DE_CONSTANTE;

Aunque eso no creo que aumente la velocidad del ajax , de hecho la alentaria en algunos casos, aumenta la seguridad de los scripts en cierto punto y de librerias extras. Asi como el script de subir imagen que estaba haciendo (creo que nadie entendio mi script, o no les servia xD).

Saludos!

PD: Tengo esta semana llena de examenes de la scool, desde que llegue he estado ayudando lo mayor que puedo y ahora que puedo ayudarte demasiado con el registro no podre hasta lo que es sabado y domingo :s, espero ayudar
[TUTORIAL :: SISTEMA DE REGISTRO DE USUARIOS :: PARTE 13]

Es posible que el visitante teclee mal la contraseña al registrarse. En ese caso, no podrá logearse, pues creerá haberla escrito bien y al cometer el error no sabrá cuál es la contraseña que puso.

Para evitar eso, suele añadirse un segundo recuadro en el formulario de registro, en el que se vuelve a pedir la contraseña por segunda vez.

Para añadir esta función, por un lado hemos de retocar el formulario del archivo formulario.php para añadir ese otro campo. Y por otro lado, hemos de añadir algunas líneas en el archivo registro.php con las que compararemos si las dos contraseñas son idénticas en ambos recuadros.

El archivo formulario.php ha de quedar así (aprovechamos la ocasión para añadir las modificaciones que nos propone SurKaiser. Gracias desde aquí!):


<?php

//incluimos configuracion.php con los datos de conexión
include_once('configuracion.php');

//Creamos el formulario de registro
echo '
<form action="registro.php" method="POST" />
Nick: <input type="text" name="nick" size="25" /><br />
Contraseña: <input type="password" name="password" size="40" /><br />
Repite la contraseña: <input type="password" name="password2" size="40" /><br />
E-mail: <input type="text" name="email" size="60" /><br />
<input type="submit" name="submit" value="Registrar" />
</form>
';

// Damos la opción de volver a la página de login si no desea registrarse
echo '<br /><a href="login.php">Login</a>'; 

?> 

Y el archivo registro.php de este otro modo:

<?php

//incluimos configuracion.php con los datos de conexión
include_once('configuracion.php');

//Comprobamos que la password y password2 son iguales, sino, volvemos a registro.php
if($_POST[password] != $_POST[password2])
    {
    echo 'Las passwords no son iguales';
    }
else if(($_POST[nick] == '') or ($_POST[password] == '') ) //Comprobamos que los campos nick y password no están en blanco
    {
    Header("Location: formulario.php"); // si están en blanco enviarmos al registro de nuevo
    }
else
    {
    //cuantos usuarios hay ya con ese nick?
    $cuantosnicks=mysql_query("SELECT nick FROM ".$tabla." WHERE nick='".$_POST["nick"]."' ");
    //cuantos usuarios hay ya con ese email?
    $cuantosemails=mysql_query("SELECT email FROM ".$tabla." WHERE email='".$_POST["email"]."' ");
    $nickrepetido = mysql_num_rows($cuantosnicks);
    $emailrepetido = mysql_num_rows($cuantosemails);
    if($nickrepetido >= 1)
        {
        echo 'El nick propuesto ya estaba registrado. Escoge otro.';
        // damos la opcion de registrarse de nuevo
        echo '<br /><a href="formulario.php">Quieres intentarlo con otro nick?</a>'; 
        }
    else if($emailrepetido >= 1)
        {
        echo 'El email propuesto ya estaba registrado. Escoge otro.';
        // damos la opcion de registrarse de nuevo
        echo '<br /><a href="formulario.php">Quieres intentarlo con otro email?</a>';
        }
    else
        {
        //introducimos el nuevo registro en la tabla users
        mysql_query("INSERT INTO $tabla (nick,password,email) values ('$_POST[nick]','$_POST[password]','$_POST[email]') ");
        echo 'Usuario registrado con éxito';
        // damos la opcion de logerase
        echo '<br /><a href="login.php">Quieres logearte?</a>';
        }
    mysql_free_result($cuantosnicks);  //liberamos memoria
    mysql_free_result($cuantosemails); //liberamos memoria
   }
?>

Tomando igualmente nota de los comentarios de los compañeros, sustituiremos la línea
include('configuracion.php');
por
include_once('configuracion.php');
en todos los archivos que llevamos hasta el momento.
Buena sintaxis de como hacer una constante,jejjeje; en cuanto al tema de Ajax aún esta por ver como lo abordaremos pues hay varias maneras y todas son interesante; habrá que ver cual es la más segura.

Para la gente que no este versada en el tema de las constante aparte de la buena definición del compadre lo interesante es que solo las tenemos que definir una vez en el documento y luego la/s podemos llamar desde cualquier otro documento con solo utilizar su nombre; al ser similares a la variables globales.

En cuanto a lo de Ajax a mi me encanta xml por eso siempre suelo utilizar ajax con xml para hacer historias pero php es muy versatil y aparte de las Jquery que tienen un buen soporte para tema de traspaso de datos; tambien hay otras alternativas en cuanto a bibliotecas; no hace mucho lei si no recuerdo mal que habia una manera de incluir ajax en un archivo php por medio de Xajax con lo cual tambien seria una buena opción para el tema de no ensuciar mucho el codigo html; por otro lado el tema de Json y si livianidad de formato para este caso no se si seria optar por una opción exagerada dado que no creo que haya tantas peticiones simultaneas como para que sea necesario o se relentice mucho el navegador dado que a priori solo de va a identificar.

Otra cosa que me tiene un poco intrigado es sobre que dtd lo vamos a montar pues se que html5 ya se esta implantando en muchas web; y dado que html5 y javascript estan tan unidos pues no seria mala idea. Por otro lado y dado que supongo que Jorge aprovechará para adaptar la web vía CMS a los dispositivos moviles; sera interesante ver como conseguir logarse desde un movil. Interesante no creeis?
No entiendo una cosa, qué tiene de diferente una variable de una constante?

Variable --> $variable = "VALOR";
Constante --> define("variable", "VALOR");

Para mostrar una variable: echo "$variable";
Para mostrar una constante: echo variable;

Viene a ser casi lo mismo, no?
Sorry por ser tan cortito, pero no sé mucho, se nota jajaja
La gran diferencia es que una constante en una variable global que a priori no se puede volver a difinir o redifinir.Y eso no se logra a priori con un variable global normal; el tema de que se llamen de la misma manera es logico. Pero como digo a una variable la puedes forzar a que tengo otro/s parametro/s pero a una constante no.
Vaya, aún tenemos bastantes fallos. Por ejemplo, alguien podría registrarse escribiendo espacios en blanco en el login, contraseña, email.... hay que inventar algo que verifique que los datos que se introducen en el formulario son consistentes, es decir, tienen sentido, que tienen toda la pinta de ser datos reales. Se nos podrían ocurrir cientos de posibilidades de datos falsos, pero escribir líneas de código para cada uno de esos casos promete ser algo terrible, verdad?

Vamos a pensar un poco y a determinar algún modo de evitar ese tipo de datos en el formulario. Establezcamos primero qué normas han de cumplir cada uno de los datos solicitados, oki?

- Nick: Podríamos decidir que solo se pudieran usar números y letras mayúsculas y minúsculas. Sin espacios en blanco ni carácteres extraños tales como acentos, barras, símbolos usados para las etiquetas de código como < y > (con esto además evitamos que nos metan códigos maliciosos mediante el formulario).

- Email: Podría contener tan solo letras minúsculas y números, pero además ha de contener la arroba y terminar en un punto seguido de la extensión. Si no se cumple eso, seguro que no es un correo real, verdad?

- Contraseña: En este caso podríamos admitir números y letras mayúsculas y minúsculas y, además, permitir algunos otros carácteres a los que suelo llamar raros. Colocando alguno de esos carácteres, disminuimos la posibilidad de que algún malvado la adivine (es múcho más segura la contraseña "se-cre-_to" que "secreto", de modo que en este caso admitiremos algunos carácteres "raros".

Dejadme que lo piense un poco y os cuento cómo solucionar esta papeleta. Seguramente crearemos un archivo que se encargue de esto, de verificar la integridad de estos datos.

Un abrazo!
[TUTORIAL :: SISTEMA DE REGISTRO DE USUARIOS :: PARTE 14]

Parece que he conseguido algo. Con unas cuantas líneas de código ahora consigo eliminar cualquier carácter extraño del nick y de la contraseña. Si el usuario las introduce, las elimino y le muestro con que nick y password ha sido registrado.

Para el email, uso una función que he encontrado por la red. Con ella nos aseguramos de que cumple con el formato normal de email, aunque por el momento no podemos saber si el correo está o no dado de alta. Posteriormente podemos hacer que el usuario tenga que responder a algún correo para validar su cuenta, por lo que en ese momento sabremos si el correo es totalmente válido, pero por ahora sabemos que el formato es correcto.

El archivo registro.php queda por tanto de este modo:

<?php

//incluimos configuracion.php con los datos de conexión
include_once('configuracion.php');

function limpia($cadena)
    {
    return (ereg_replace('[^A-Za-z0-9_-ñÑ]', '', $cadena));
    }

// definimos las variables
$nick     = limpia($_POST['nick'])     ;
$email    = $_POST['email']            ;
$password = limpia($_POST['password']) ;
$password2= limpia($_POST['password2']);

// Si hay algún campo vacio abortamos y avisamos del error
if ( empty($nick) OR empty($email) OR empty($password) OR empty($password2) )
{
   header("Refresh: 5; URL=formulario.php");
   echo "<p>ERROR. Los datos introducidos no tienen un formato correcto.</p>";
   die;
}

function verificar_email($email) 
   {
   // Verificamos que no hay más de una arroba y que las longitudes son normales
   if (!ereg("^[^@]{1,64}@[^@]{1,255}$", $email)) 
      {
      return false;
      }
   $email_array = explode("@", $email);
   $local_array = explode(".", $email_array[0]);
   for ($i = 0; $i < sizeof($local_array); $i++) 
      {
      if (!ereg("^(([A-Za-z0-9!#$%&'*+/=?^_`{|}~-][A-Za-z0-9!#$%&'*+/=?^_`{|}~\.-]{0,63})|(\"[^(\\|\")]{0,62}\"))$", $local_array[$i])) 
         {
         return false;
         }
      } 
   // se revisa si el dominio es una IP. Si no, debe ser un nombre de dominio válido
   if (!ereg("^\[?[0-9\.]+\]?$", $email_array[1])) 
      { 
      $domain_array = explode(".", $email_array[1]);
      if (sizeof($domain_array) < 2) 
         {
         return false; // No son suficientes partes para ser un dominio
         }
      for ($i = 0; $i < sizeof($domain_array); $i++) 
         {
         if (!ereg("^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]+))$", $domain_array[$i])) 
            {
            return false;
            }
         }
      }
      return true;
   }

   if ( verificar_email($email)==false )
      {
      header("Refresh: 5; URL=formulario.php");
      echo "<p>ERROR. El Email $email no parece ser real.</p>";
      die;
      }

//Comprobamos que la password y password2 son iguales, sino, volvemos a registro.php
if($password != $password2)
    {
    echo 'ERROR. Las passwords no coinciden';
    }
else
    {
    //cuantos usuarios hay ya con ese nick?
    $cuantosnicks=mysql_query("SELECT nick FROM ".$tabla." WHERE nick='".$nick."' ");
    //cuantos usuarios hay ya con ese email?
    $cuantosemails=mysql_query("SELECT email FROM ".$tabla." WHERE email='".$email."' ");
    $nickrepetido = mysql_num_rows($cuantosnicks);
    $emailrepetido = mysql_num_rows($cuantosemails);
    if($nickrepetido >= 1)
        {
        echo 'El nick propuesto ya estaba registrado. Escoge otro.';
        // damos la opcion de registrarse de nuevo
        echo '<br /><a href="formulario.php">Quieres intentarlo con otro nick?</a>'; 
        }
    else if($emailrepetido >= 1)
        {
        echo 'El email propuesto ya estaba registrado. Escoge otro.';
        // damos la opcion de registrarse de nuevo
        echo '<br /><a href="formulario.php">Quieres intentarlo con otro email?</a>';
        }
    else
        {
        //introducimos el nuevo registro en la tabla users
        mysql_query("INSERT INTO $tabla (nick,password,email) values ('$nick','$password','$email') ");
        echo "<br /><p>Usuario registrado con éxito con Nick=$nick, Contraseña=$password y email=$email</p>";
        // damos la opcion de logerase
        echo '<br /><a href="login.php">Quieres logearte?</a>';
        }
    mysql_free_result($cuantosnicks);  //liberamos memoria
    mysql_free_result($cuantosemails); //liberamos memoria
   }
?> 
Sigo atento a vuestros comentarios sobre el uso de las constantes. Seguro que si se pueden aprovechar en esta aplicación, le daremos buen uso.

En cuanto a la posibilidad de logearse desde el movil.... no deshecho la idea, desde luego. Aunque habrá que ir pasito a pasito, je je je.

Para la próxima, quiero añadir algunas líneas que envian algo así como testigos, para asegurarse de que los datos provienen del formulario y no de algún craker. Lo maduro un poco más y os lo muestro en la próxima parte. Ahora a la cama que ya es hora, je je je.

Gracias a todos por colaborar!
Todo bien, solo un comentario, las funciones del tipo ereg() estan declaradas obsoletas apartir de PHP 5.3.0 y por lo tanto su uso no es recomendado amenos que trabajes con php 4, en su lugar se usaria preg_match().