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) sen 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. Para verificar o tipo de dato coas funcións is_XXXXX (coma por exemplo is_string) non se poden utilizar con datos que veñan a través dun formulario, xa que todos eles son avaliados como de tipo String.
É dicir, un dato que garde a idade, por exemplo, se teño a variable $idade=3; e aplico a función is_string($idade) vai devolver false, pero se o dato da idade (valor 3) ven dun formulario e aplico a mesma función is_string($_POST['txtIdade']) vai devolver true.
1 if (empty($_POST['txtNome'])) echo('Campo nome non ten datos');
  • 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 convertelo a Integer.


Comprobando se chegan datos de varios formularios diferentes á mesma páxina

  • Imaxinemos o caso de que temos unha páxina de nome primeira.php. Dita páxina ten un formulario cuxo 'action' apunta a unha segunda páxina de nome: segunda.php
Imaxinemos que dita páxina segunda.php ten a súa vez un formulario cuxo action apunta a ela mesma.
Neste caso temos que identificar 3 posibles casos cando carguemos a páxina segunda.php:
  • A páxina se carga vindo do primeiro formulario. Para identificar este caso podemos facer uso do botón de tipo 'submit' e definilo da seguinte maneira:
<input name='btnEnviar1' type='submit' value='Envía datos páxina 1' />
Na páxina segunda.php podemos poñer a seguinte condición para saber se ven da primeira.php:
if (!empty($_POST['btnEnviar1'])) { } => Sabemos que vimos da primeira
  • A páxina se carga vindo de segunda.php
Podemos facer algo parecido á anterior e definir un name para o botón que fai o submit dende a segunda:
<input name='btnEnviar2' type='submit' value='Envía datos páxina 1' />
Na páxina segunda.php podemos poñer a seguinte condición para saber se ven da segunda.php:
if (!empty($_POST['btnEnviar2'])) { } => Sabemos que vimos da segunda páxina.
  • Se cargamos a páxina segunda.php directamente, o sabemos porque:
if (empty($_POST['btnEnviar1']) && empty($_POST['btnEnviar2'])) { } => Sabemos que cargamos a páxina directamente sen vir dende primeira.php nin de segunda.php

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 Se non poñemos un flag, non admitirá números decimais.
  • 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. Pode levar como terceiro parámetro algún destes flag´s:
  • FILTER_FLAG_NO_ENCODE_QUOTES - Non codifica as comillas simples ou dobres (non as substitúe por códigos &#39 => ' por exemplo)
  • FILTER_FLAG_STRIP_LOW - Elimina caracteres cun código ASCII < 32
  • FILTER_FLAG_STRIP_HIGH - Elimina caracteres cun código ASCII > 127
  • FILTER_FLAG_ENCODE_LOW - Codifica caracteres cun código ASCII < 32
  • FILTER_FLAG_ENCODE_HIGH - Codifica caracteres cun código ASCII > 127
  • FILTER_FLAG_ENCODE_AMP - Codifica o carácter "&" con &
Nota: Pódense combinar varios flag´s con |
  • 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'.

Corrixindo os valores

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


  • Corrixindo un número flotante.
1 <?php
2 $number="53.3pp";
3 
4 var_dump(filter_var($number, FILTER_SANITIZE_NUMBER_FLOAT,
5 FILTER_FLAG_ALLOW_FRACTION));  // Este flag fai que o caracter 'punto' sexa válido (separador de decimais)
6 ?>
Devolve '53.3'.

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'


  • Nota: Podemos facer uso da función filter_input que permite obter un dato dun formulario e validar ao mesmo tempo.

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 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.


  • Outro exemplo é se empregamos a variable $_SERVER['PHP_SELF'] como parámetro nun action dun formulario da forma:
1 <form method="post" action="<?php echo $_SERVER['PHP_SELF']); ?>" name="formulario_perfumes">
2 
3 ......
4 
5 </form>


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: & lt;script& gt;window.location=& quot;http://www.google.es& quot;;& lt;/script& gt;
Fixarse que os caracteres < e > son substituídos por & lt; e & gt; respectivamente.
(Hai posto un espazo en branco entre & e o código xa que se non a wiki o visualizará como html)


No caso do formulario poderíamos poñer:

<form method="post" action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>" name="formulario_perfumes">

......

</form> </syntaxhighlight>

Obtendo variables de formularios (post/get) e filtrado ao mesmo tempo

  • En PHP , a partires da versión 5, podemos recuperar o valor dun campo dun formulario e aplicarlle un filtro ao mesmo tempo.
A función que permite facer isto é filter_input.
  • Sintaxe:
1 mixed filter_input ( int $type , string $variable_name [, int $filter = FILTER_DEFAULT [, mixed $options ]] )
Parámetros:
  • type: INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER o INPUT_ENV.
  • variable_name: Nome da variable, ven ser o nome da control html en caso dun formulario.
  • filter: O ID do filtro a aplicar. Xa os vimos neste mesmo punto da wiki.
  • options: Array asociativo de opcións. Se o filtro acepta opcións, se poden engadir nun array asociativo baixo la clave "flags".
Valores devoltos:
  • En caso de éxito, valor da variable pedida, FALSE se o filtro faia ou NULL se a variable variable_name non está definida.
  • Por exemplo:
1 <?php
2 $buscar_html = filter_input(INPUT_GET, 'buscar', FILTER_SANITIZE_SPECIAL_CHARS);
3 $buscar_url = filter_input(INPUT_GET, 'buscar', FILTER_SANITIZE_ENCODED);
4 echo "Has buscado $buscar_html.\n";
5 echo "<a href='?buscar=$buscar_url'>Buscar de nuevo</a>";
6 ?>


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.

Quere isto dicir que ao cliente non lle pode chegar ningunha etiqueta HTML antes de facer o header-location. Non vale se temos un echo/printf de calquera cousa ou código HTML enviado antes da orde header.


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.

Gardando imaxes no servidor

  • Nos formularios temos a posibilidade de subir arquivos ao servidor.
Un uso típico pode ser o de gardar documentos ou dar de alta produtos con imaxes asociadas. Neste último caso, o que gardaremos na base de datos será o nome do arquivo da imaxe (por exemplo 'imaxe.jpg') e cando recuperemos os datos da base de datos 'construiremos' unha etiqueta <img src='http://www.meusitio.es/IMAXES/imaxe.jpg' /> sendo IMAXES o cartafol onde están gardadas as imaxes no meu servidor web que atende a peticións coa URL: http://www.meusitio.es


  • O primeiro que teremos que facer é crear un cartafol onde queiramos deixar as imaxes no noso servidor web.
Como vimos na wiki nun punto anterior, o servidor web Apache 'apunta' fisicamente por defecto a '/var/www/html'.
Crearemos (podedes comprobar a onde apunta mirando o arquivo de configuración /etc/apache2/sites-available/000-default.conf, como está explicado na wiki) un cartafol de nome IMAXES e darémoslle permiso de escritura ao usuario que utiliza o servidor Apache para acceder ao sistema de arquivos (www-data). Isto último está explicado no seguinte punto da wiki.


  • Supoñemos que document_root apunta a /var/www/html e que estades a utilizar como servidor web Apache instalado de forma independente (sen XAMPP)
Supoñemos que estades a utilizar Apache como servidor web e que o usuario-grupo que utiliza é www-data
1 cd /var/www/html
2 mkdir IMAXES
3 chown www-data:www-data IMAXES
4 chmod 755 IMAXES


Se estiverades a utilizar XAMPP, teredes que mirar o arquivo de configuración do Apache que no caso de XAMPP é o httpd.conf que se atopa no cartafol /opt/lampp/etc
 1 <IfModule unixd_module>
 2 #
 3 # If you wish httpd to run as a different user or group, you must run
 4 # httpd as root initially and it will switch.
 5 #
 6 # User/Group: The name (or #number) of the user/group to run httpd as.
 7 # It is usually good practice to create a dedicated user and group for
 8 # running httpd, as with most system services.
 9 #
10 User daemon
11 Group daemon
12 </IfModule>
Nas liñas 10 e 11 se indica o usuario e grupo que utiliza o Apache de XAMPP para acceder aos cartafoles.
Deberedes cambiar a liña do script anterior de chown www-data:www-data IMAXES a chown daemon:daemon IMAXES



Páxina do formulario

  • A páxina onde se atopa o formulario para subir entre outros campos o campo imaxe debe ter as seguintes características.
Información obtida de www3schools.
 1 <!DOCTYPE html>
 2 <html>
 3 <body>
 4 
 5 <form action="GardaCampos.php" method="post" enctype="multipart/form-data">
 6     Selecciona unha imaxe para subir:
 7     <input type="file" name="fileToUpload" id="fileToUpload">
 8     <input type="submit" value="Subir Imaxe" name="btnSubirImaxe">
 9 </form>
10 
11 </body>
12 </html>

IMPORTANTE:

  • Liña 5: Debemos de escribir enctype="multipart/form-data" na etiqueta form en caso de querer subir arquivos a un servidor.
  • Liña 7: O elemento HTML para poder seleccionar unha imaxe debe ser de tipo file
  • Agora o Action do formulario pode 'apuntar' á mesma páxina ou a outra para procesar a subida do arquivo.


Páxina que procesa os datos

Pode ser a mesma do formulario ou outra diferente. No exemplo se chama 'GardaCampos.php'.
 1 <?php
 2 $uploadOk=0;
 3 
 4 // Enviamos datos
 5 if(isset($_POST["btnSubirImaxe"])) {
 6     $target_dir = $_SERVER['DOCUMENT_ROOT'] . "/IMAXES/";  // Gardaremos a imaxe no cartafol a onde apunta o servidor web máis /IMAXES => /var/www/html/IMAXES
 7     $target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);  // Colle o nome da imaxe. Isto é necesario se a imaxe ten unha ruta posta no seu nome. 
 8 
 9     $uploadOk = 1;
10     $imageFileType = pathinfo($target_file,PATHINFO_EXTENSION);
11     $check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
12     if($check !== false) {
13         echo "O arquivo é unha imaxe - " . $check["mime"] . ".";
14         $uploadOk = 1;
15     } else {
16         echo "O arquivo non é unha imaxe.";
17         $uploadOk = 0;
18     }
19 
20     if ($uploadOk == 0) {
21         echo "A imaxe non foi subida.";
22     } else {
23         if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
24             echo "O arquivo ". basename( $_FILES["fileToUpload"]["name"]). " foi subido ao servidor.";
25         } else {
26             echo "Houbo un erro subido o arquivo.";
27         }
28     }
29 }
30 
31 
32 ?>
  • Liña 5: Preguntamos se veñen datos do formulario anterior
  • Liña 7: A función basename devolve a última parte dunha ruta. Así se teño c:\carpeta1\carpeta2\arquivo.jpg devolverá 'arquivo.jpg'.
  • Liña 10: A función pathinfo garda a extensión do arquivo a subir.
  • Liña 11: A función getimagesize devolve un array con información da imaxe. En caso de que non sexa unha imaxe devolve false.
  • Liña 23: En caso de que todo estea correcto movemos a imaxe que se atopa non cartafol temporal no servidor ao cartafol indicado por nos na variable $target_file


  • Debemos ter en conta que podemos subir outro tipo de arquivos, como documentos,...iso dependerá da nosa aplicación.
Podemos mellorar o noso código introducindo novas condicións.


  • Verificar se o arquivo existe antes de subilo:
1 <?php
2 if (file_exists($target_file)) {
3     echo "Ese arquivo xa existe.";
4     $uploadOk = 0;
5 } 
6 ?>


  • Limitar o tipo do arquivo:
1 <?php
2 if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg"
3 && $imageFileType != "gif" ) {
4     echo "Soamente arquivos JPG, JPEG, PNG & GIF están permitidos.";
5     $uploadOk = 0;
6 } 
7 ?>


  • Limitar o tamaño do arquivo:
1 <?php
2  // Check file size
3 if ($_FILES["fileToUpload"]["size"] > 500000) {
4     echo "O arquivo ten máis de 500KB. Non se pode subir";
5     $uploadOk = 0;
6 } 
7 ?>


Comentar que o referente ao tamaño dos arquivos, imos ter a limitación imposta polo propio PHP.
Se estades non aloxamento compartido non ides poder modificar o arquivo de configuración para permitir subir arquivos de máis de 8MB.
Existen dúas entradas no arquivo de configuración php.ini que son:
upload_max_filesize = 2M;
post_max_size = 8M;
Estas directivas indican o tamaño máximo dun arquivo a subir e o tamaño máximo dun formulario incluíndo todos os seus campos.
Lembrar que o arquivo de configuración de PHP se atopa en:
  • /etc/php5/apache2/php.ini se estados a utilizar un servidor web Apache instalado independentemente.
  • /etc/php5/cli/php.ini se estados a utilizar XAMPP.
Se queredes aumentar o tamaño deberedes cambiar ambas directivas aos valores desexados.
Tedes no meu Blog unha entrada do que hai que facer no caso de estar nun aloxamento compartido.
No blog se explica os pasos para aplicar no Moodle, pero podería aplicarse en outros escenarios.


Teríamos varias opcións, sempre supoñendo que o aloxamento compartido deixe crear arquivos php.ini ou .htaccess que sobrescriban a configuración do servidor web Apache (isto normalmente é así).
  • Opción a)
Crear un arquivo php.ini no cartafol raíz do noso sitio web e poñer:
1 upload_max_filesize = 64M
2 post_max_size = 64M
3 max_execution_time = 300
No exemplo estamos a limitar en 64MB o tamaño da subida e o tempo de execución en 5 minutos.
  • Opción b)
Crear un arquivo .htaccess no cartafol raíz do noso sitio web e poñer:
1 php_value upload_max_filesize 64M
2 php_value post_max_size 64M
3 php_value max_execution_time 300
4 php_value max_input_time 300
No exemplo estamos a limitar en 64MB o tamaño da subida e o tempo de execución en 5 minutos.




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