PHP Paso de datos con formularios

De MediaWiki
Ir a la navegación Ir a la búsqueda

Introdución

  • Sabemos que a través da etiqueta <form> podemos enviar datos dunha páxina a outra.
  • Dentro de esta etiqueta temos o atributo method que pode tomar os valores get ou post.

Método GET

Os datos que aparecen despois do signo '?' son parámetros:?q=php&ie=utf-8&oe=utf-8


  • Desvantaxes:
  • Calquera persoa pode ver os valores das variables polo que dito método non é moi seguro.
  • O usuario pode cambiar o valor de ditas variables polo que pode suceder que o sitio amose ou faga algo diferente do permitido.
  • O usuario pode obter información non actual se usa unha URL con datos non actualizados.
  • O tamaño do que podemos enviar na URL está limitado (depende de cada navegador, pero pode estar entre 2KB-8KB)
  • Vantaxes:
  • A través da URL podemos pasar datos dunha páxina a outra sen necesidade de ter un formulario por medio.


  • As variables que se pasan desta forma poden ser referenciadas en PHP a través da matriz global $_GET['param'].


  • Vexamos agora un exemplo utilizando un formulario:

Arquivo: UD2_Form_Ex1_eleccion_pelicula.php

 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 2     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 3 <html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es">
 4     <head>
 5         <meta charset="utf-8" />
 6         <title>Formulario</title>
 7         <style>
 8             .formularios{
 9                 width: 30%;
10                 margin: 0px auto;
11             }
12             .etiqueta{
13                 float: left;
14                 width: 190px;
15             }
16             .botonesformularios{
17                 width: 50%;
18                 margin: 30px auto;
19                 text-align: center;
20             }
21             select {
22                 width:50%;
23             }
24         </style>
25     </head>
26     <body>
27         <form id="frmPelicula" class="formularios" method="get" action="UD2_Form_Ex1_datos_pelicula.php">
28             <div>    
29                 <div class='etiqueta'>Película preferida:</div>
30                 <select name="lstPelicula"><option>E.T. El extraterrestre</option><option>Supermán</option></select>
31             </div>                
32             <div>
33                 <div class='etiqueta'>Xénero preferido:</div>
34                 <select name="lstXenero"><option>Acción</option><option>Ciencia ficción</option></select>
35             </div>                
36             <div class="botonesformularios">
37                 <input type='submit' value="ENVIAR" />
38             </div>
39         </form>
40 
41     </body>    
42 </html>
43 </php>
  • Fixarse que enviamos os datos utilizando o método get.

Arquivo: UD2_Form_Ex1_datos_pelicula.php

 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 2     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 3 
 4 <html>
 5     <head>
 6         <meta charset="UTF-8">
 7         <title></title>
 8     </head>
 9     <body>
10         <?php
11         echo 'Os datos que escolliches son:<br/><br/>';
12         
13         $pelicula = $_GET['lstPelicula'];
14         $xenero = $_GET['lstXenero'];
15 
16         printf("PELICULA:%s<br/>XÉNERO:%s",$pelicula,$xenero);
17         ?>
18         
19     </body>
20 </html>



Método POST

  • No método post de envío de datos, os mesmos van 'dentro' da páxina web e polo tanto non son visibles para o usuario.
  • Tamén está limitado o tamaño do que se pode enviar (por exemplo se enviamos un arquivo adxunto) a un tamaño de 8MB.
Podemos cambiar dito límite:
  • Modificando a directiva post_max_size do arquivo php.ini de PHP.
  • Modificando o arquivo .htaccess do noso sitio web e engadindo a directa: php_value post_max_size 20M (isto é necesario no caso de aloxamentos compartidos ou se non temos acceso ao arquivo php.ini).
Nota: No caso de subir arquivos tamén pode ser necesario modificar a directiva upload_max_filesize do arquivo php.ini
Podedes ver neste enlace como aumentar o tamaño dos arquivos subidos nun aloxamento compartido.


  • As variables que se pasan desta forma poden ser referenciadas en PHP a través da matriz global $_POST['param'].


  • Modificamos o exemplo anterior para que envíe os datos con POST:

Arquivo: UD2_Form_Ex2_eleccion_pelicula.php

 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 2     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 3 <html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es">
 4     <head>
 5         <meta charset="utf-8" />
 6         <title>Formulario</title>
 7         <style>
 8             .formularios{
 9                 width: 30%;
10                 margin: 0px auto;
11             }
12             .etiqueta{
13                 float: left;
14                 width: 190px;
15             }
16             .botonesformularios{
17                 width: 50%;
18                 margin: 30px auto;
19                 text-align: center;
20             }
21             select {
22                 width:50%;
23             }
24         </style>
25     </head>
26     <body>
27         <form id="frmPelicula" class="formularios" method="post" action="UD2_Form_Ex2_datos_pelicula.php">
28             <div>    
29                 <div class='etiqueta'>Película preferida:</div>
30                 <select name="lstPelicula"><option>E.T. El extraterrestre</option><option>Supermán</option></select>
31             </div>                
32             <div>
33                 <div class='etiqueta'>Xénero preferido:</div>
34                 <select name="lstXenero"><option>Acción</option><option>Ciencia ficción</option></select>
35             </div>                
36             <div class="botonesformularios">
37                 <input type='submit' value="ENVIAR" />
38             </div>
39         </form>
40 
41     </body>    
42 </html>
43 </php>
  • Fixarse que enviamos os datos utilizando o método post.

Arquivo: UD2_Form_Ex2_datos_pelicula.php

 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 2     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 3 
 4 <html>
 5     <head>
 6         <meta charset="UTF-8">
 7         <title></title>
 8     </head>
 9     <body>
10         <?php
11         echo 'Os datos que escolliches son:<br/><br/>';
12         
13         $pelicula = $_POST['lstPelicula'];
14         $xenero = $_POST['lstXenero'];
15 
16         printf("PELICULA:%s<br/>XÉNERO:%s",$pelicula,$xenero);
17         ?>
18         
19     </body>
20 </html>

Comprobando se hai datos

  • Normalmente a páxina que recibe os datos vai facer algún tipo de tratamento con eles (por exemplo, facer unha alta nunha táboa dunha base de datos, consultar en base aos criterios recibidos,...)
  • Polo tanto será necesario realizar algún tipo de validación para comprobar se se envían os datos necesarios e estes teñen un formato correcto.
Lembrar repasar as funcións que comproban se un campo ten datos e as funcións que comproban o tipo de dato dunha variable.


1 if (empty($_POST)) die('Non se enviaron datos');

Nota: A función die ao igual que a función exit finaliza a páxina php.

O tratamento que queiramos darlle á páxina cando non se envíen datos será decidido polo programador, pudendo enviarlle un aviso ao usuario en enviando de novo a páxina do formulario.
Tede que ter en conta que aínda que fagades unha validación dos campos utilizando javascript, isto pódese saltar, xa que a páxina está no cliente. Ademais un usuario podería cargar a páxina de tratamento da información (a que está indicada no action do formulario) se pasar polo formulario.


  • O segundo será verificar que os campos teñan algún valor (se é obrigatorio) e que o tipo de dato sexa o correcto.
1 if (empty($_POST['txtNome'])) echo('Campo nome non ten datos');
2 if (!is_string($_POST['txtNome'])) echo('Campo nome non é unha cadea');



  • IMPORTANTE: Todos os datos que veñen no array global $_POST son de tipo String. Teremos que facer un 'cast' ao tipo de dato ou ven utilizar a función filter_var que será explicada a continuación.
Facendo o cast podemos saber se é un número ou non da seguinte forma:
1 if (ctype_digit($_POST['txtIdade'])){
2      $idade = (int)$_POST['txtIdade'];
3 }
4 else {
5      echo 'Non é numérico integer';
6 }
Usamos a función ctype_digit para comprobar se temos díxitos numéricos no dato enviado.
O cast (int) vai devolver 0 en caso de que non poida convertilo a Integer.

Función para validar / corrixir campos

  • O proceso de validación-corrección de campos dun formulario soe ser dar bastante traballo.
Para facernos a vida un pouco máis doada, temos unha extensión en PHP que permite a validación de campos dunha forma moi sinxela.
A función filter_var permítenos filtrar unha variable segundo o filtro indicado.
Parámetros:
  • $var: Variable que se quere filtrar
  • $filter: Filtro que se desexa aplicar. Será una constante numérica (indicadas a continuación)
  • $options: Conxunto de opcións que modifican o funcionamento do filtro. Pode ser unha constante numérica ou un array
Valor devolto:
  • O dato filtrado ou false se o filtro faia.


Filtros para a validación

  • FILTER_VALIDATE_BOOLEAN => Valida a variable coma un booleano.
  • FILTER_VALIDATE_EMAIL => Valida a variable coma unha dirección de correo electrónico correcta.
  • FILTER_VALIDATE_FLOAT => Valida que a variable sexa do tipo float.
  • FILTER_VALIDATE_INT => Valida a variable coma un número enteiro.
  • FILTER_VALIDATE_IP => Valida a variable coma unha dirección IP.
  • FILTER_VALIDATE_REGEXP => Valida a variable contra unha expresión regular enviada na variable de opcións.
  • FILTER_VALIDATE_URL => Valida o valor coma unha URL de acordo coa RFC 2396.


Filtros para a corrección

  • FILTER_SANITIZE_EMAIL => Elimina tódolos caracteres execepto letras, números e !#$%&’*+-/=?^_`{|}~@.[].
  • FILTER_SANITIZE_ENCODED => Codifica a cadea coma unha URL válida.
  • FILTER_SANITIZE_MAGIC_QUOTES => Aplica a función addslashes.
  • FILTER_SANITIZE_NUMBER_FLOAT => Elimina tódolos caracteres excepto números, +- e opcionalmente ,.eE
  • FILTER_SANITIZE_NUMBER_INT => Elimina tódolos caracteres excepto números e os signos + -
  • FILTER_SANITIZE_SPECIAL_CHARS => Escapa caracteres HTML e caracteres con ASCII menor a 32.
  • FILTER_SANITIZE_STRING => Elimina etiquetas, opcionalmente elimina ou codifica caracteres especiais.
  • FILTER_SANITIZE_STRIPPED => Alias do filtro anterior.
  • FILTER_SANITIZE_URL => Elimina tódolos caracteres excepto números, letras y $-_.+!*’(),{}|\\^~[]`<>#%”;/?:@&=

Exemplos

Validando

  • Validando un número enteiro
1 <?php  
2     $var = 123;  
3     echo filter_var($var, FILTER_VALIDATE_INT);  
4 ?>
Devolve o número xa que é un enteiro.
  • Validando un número enteiro
1 <?php  
2     $var = -2.343;  
3     if(filter_var($var, FILTER_VALIDATE_INT) === false){  
4         echo 'Valor incorrecto';  
5     }else{  
6         echo 'Valor correcto';  
7     }  
8 ?>
Devolve 'Valor incorrecto' xa que non é un enteiro e polo tanto a función devolve false.
  • Validando un número enteiro
1 <?php  
2     $var = '-2';  
3     if(filter_var($var, FILTER_VALIDATE_INT) === false){  
4         echo 'Valor incorrecto';  
5     }else{  
6         echo 'Valor correcto';  
7     }  
8 ?>
Devolve 'Valor correcto'.


  • Validando un número flotante
1 <?php
2     $var = '-1.45';  
3     if(filter_var($var, FILTER_VALIDATE_FLOAT) === false){  
4         echo 'Valor incorrecto';  
5     }else{  
6         echo 'Valor correcto';  
7     }  
8 ?>
Devolve 'Valor correcto'.


  • Validando un email
1 <?php  
2     $var = 'casa@hotmail';  
3     if (!filter_var($var,FILTER_VALIDATE_EMAIL)){
4         echo "Valor incorrecto";
5     }else{  
6         echo 'Valor correcto';  
7     }  
8 ?>
Devolve 'Valor incorrecto'.

Correxindo os valores

  • Cunha serie de filtros (SANITIZE) podemos eliminar aqueles caracteres que non queremos que aparezan nun determinado campo.
  • Elimando etiquetas dentro dun textarea.
1 <?php  
2     $var = '<isto non está permitido> Isto si aparece';  
3     echo filter_var($var,FILTER_SANITIZE_STRING);
Devolve 'Isto si aparece'.

Establecendo criterios

  • Podemos indicar que rango de valores son aceptables polo filtro.
  • Validando un número enteiro dentro dun rango
 1 <?php  
 2     $var = -200;  
 3     $opciones = array(
 4         'options' => array(
 5         'min_range' => 10,
 6         'max_range' => 100
 7     ));
 8       
 9     if(filter_var($var, FILTER_VALIDATE_INT, $opciones) === false){  
10         echo 'Valor incorrecto';  
11     }else{  
12         echo 'Valor correcto';  
13     }  
14 ?>
Devolve 'Valor incorrecto'


  • Podemos facer unha modificación para que en caso incorrecto devolva sempre un valor 'por defecto':
 1 <?php  
 2     $var = -200;  
 3     $opciones = array(
 4         'options' => array(
 5         'default' => 3, // valor a retornar se o filtro faiaa
 6         'min_range' => 10,
 7         'max_range' => 100
 8     ));
 9       
10     $var = filter_var($var, FILTER_VALIDATE_INT, $opciones);
11     echo $var;
12 
13 ?>
Neste caso $var valerá '3' en caso de que non se cumpra o filtro.


  • No caso dun número flotante podemos indicar cal é o carácter separado dos díxitos decimais.
 1 <?php  
 2     $var = '1,23';  
 3     $opciones = array(
 4         'options' => array(
 5         'decimal' => ','
 6     ));
 7       
 8     if(filter_var($var, FILTER_VALIDATE_FLOAT, $opciones) === false){  
 9         echo 'Valor incorrecto';  
10     }else{  
11         echo 'Valor correcto';  
12     }  
13 ?>
Devolve 'Valor correcto'

Validación de datos utilizando arrays

  • Cando vexamos os arrays, podemos comprobar como facer unha validación de campos dunha forma máis rápida.



Seguridade no uso dos formularios

  • Cando manexamos formularios temos que ter precaución co manexo de datos, xa que un usuario malintencionado podería poñer en risco o noso sitio web.

Inxección de CSS

  • Este problema aparece normalmente cando temos unha caixa de texto / textarea no que imos a engadir/consultar, cos datos que veñen, a unha táboa dunha base de datos.


Unha consulta clásica de validación de usuario podería ser:
  • $_POST['usuarios'] = 'angel'
  • $_POST['password'] = '12345678'
1 <?php
2             $nome=$_POST['usuarios'];
3             $password=$_POST['password'];
4                       
5             printf("select count(*) from USUARIOS where nome='%s' and password='%s'",$nome,$password);
6 ?>
Neste caso se a consulta devolve 1 entón é un usuario da nosa base de datos.
A consulta a executar no xestor de base de datos sería: select count(*) from USUARIOS where nome='angel' and password='12345678'
  • Agora modifiquemos o campo password e imaxinemos que o usuario pon isto:
  • $_POST['password'] = "' or password like '%";
O resultado da consulta sería: select count(*) from USUARIOS where nome='angel' and password= or password like '%'
  • Como vemos estamos saltándonos a seguridade debido a que:
  • O usuario pode engadir máis texto do permitido (incluso poñendo restricións de javascript, estas poden ser saltadas).
  • O usuario pode engadir 'texto' que non debería estar permitido.

Nota: En vez de modificar unha consulta (como no exemplo) podería executar ordes SQL como de inserción, borrado ou modificación de rexistros.

Solución a inxección de CSS

  • A mellor solución é utilizar procedementos almacenados. Sempre que o xestor o permite.
Vexamos un exemplo en Mysql:
1 DELIMITER //
2 CREATE PROCEDURE country_hos
3 (IN log VARCHAR(20),IN pass VARCHAR(30))
4 BEGIN
5   SELECT count(*) FROM USUARIOS
6   WHERE login = log and password = pass;
7 END //
8 DELIMITER ;
Nesta solución temos:
  • O usuario aínda que envíe máis información so se vai coller 20 caracteres para o login e 30 para o password.
  • Aínda que engada 'código SQL' non se vai a executar xa que dito código vai ir todo na campo password.
Loxicamente isto non quita que busquemos formas de validar os datos introducidos.


  • Outra opción é a de utilizar funcións que provea o S.X.B.D. utilizado.
No caso de mysql temos a ]http://php.net/manual/es/mysqli.real-escape-string.php función mysqli_real_escape_string]. O veremos cando cheguemos a sección de acceso a datos.

Cross-Site Scripting (XSS)


  • Este tipo de ataque é debido a que un usuario engade código script (coma javascript) á información que imos amosar na páxina web.
Polo tanto teremos que vixiar os datos que VISUALICEMOS na páxina.


Un exemplo sería se introducimos dentro dun text-area este código:
1 <script>window.location="http://www.google.es";</script>
O que vai pasar é que o navegador cando cargue a páxina vai cargar a páxina de google indicada no código javascript.
Fixarse no perigo que supón xa que un atacante pode levar a un usuario a outro sitio web diferente.
  • Outro exemplo de ataque por URL:
http://localhost/PhpOlaMundo/Formularios/datosFormulario.php?texto=<script>window.location="http://www.google.es";</script>
Se amosamos o dato: $_GET['texto'] teremos o mesmo problema que o anterior.


  • Este código pode vir embebido nunha folla de estilos CSS, nun atributo dunha etiqueta HTML, dentro do corpo da páxina,na URL...

Importante: Fixarse que neste tipo de ataques temos que evitar que o que visualizamos leve código de script embebido. É diferente ao anterior no que supoñía un ataque á base de datos.


Solucións ao ataque Cross-Site Scripting (XSS)

  • Igual que no caso anterior podemos utilizar a función filter_var cos filtros FILTER_SANITIZE_MAGIC_QUOTES ou FILTER_SANITIZE_STRING para eliminar dita posibilidade.
  • En PHP podemos facer uso das seguintes funcións:
  • Función strip_tags: Dita función fai o mesmo que FILTER_SANITIZE_STRING e ademais podemos indicar cales etiquetas son permitidas.
  • Función htmlentities: Dita función substitúe os caracteres das etiquetas en códigos HTML para a súa visualización.
Se aplicamos dita función ao exemplo anterior teríamos esta saída coma código fonte de páxina: <script>window.location="http://www.google.es%22;</script>
Fixarse que os caracteres < e > son substituídos por < e > respectivamente.

Redireccionamento de páxinas

  • Pode ser interesante cando realizamos un tratamento cos datos que veñen dun formulario ter a posibilidade de mandar ao usuario a unha páxina concreta.
Imaxinemos o caso de que intentamos cargar a páxina de tratamento dun formulario previo ou que enviamos datos que non están completos. Neses casos queremos volver a enviar ao usuario á páxina de entrada de datos.
Dita función serve para enviar encabezados ao navegador do cliente. Uns destes encabezados serve para redireccionar a páxina do clienta. A forma de facelo é:
1 <?php
2 header('Location: http://www.nova_paxina.es/');
3 exit;
4 ?>

Importante: É NECESARIO QUE A CHAMADA Á FUNCIÓN header SE FAGA ANTES DE ENVIAR NINGÚN DATO AO CLIENTE.


Ao instalalo teremos a posibilidade de capturar os datos de cabeceira da páxina se imos ao menú Herramientas => Live HTTP Headers.
Coa función header imos poder manipular os datos enviados ao cliente dende o servidor.




-- Ángel D. Fernández González -- (2016).