Diferencia entre revisiones de «PHP Paso de datos na URL»

De MediaWiki
Ir a la navegación Ir a la búsqueda
Línea 1: Línea 1:
−
==Paso de datos==
+
== Paso de datos pola URL ==
  
−
* Unha forma de pasar información de unha páxina a outra é a través dunha [https://es.wikipedia.org/wiki/Localizador_de_recursos_uniforme URL].
+
* Unha forma de pasar información dunha páxina a outra é a través dunha [https://es.wikipedia.org/wiki/Localizador_de_recursos_uniforme URL].
  
−
* Se vos fixades cando facedes unha busca en google (por exemplo buscade 'php') na url aparecerá algo coma isto: https://www.google.es/search?q=php&ie=utf-8&oe=utf-8&client=firefox-b&gfe_rd=cr&ei=a1XgV4CmOu6s8wfuibOQAQ
+
* Cando unha URL leva datos despois do carácter '''?''', estes datos forman a denominada '''cadea de consulta''' ou ''query string''.
−
: Os datos que aparecen despois do signo '?' son parámetros:?'''q'''=php&'''ie'''=utf-8&'''oe'''=utf-8
 
−
: O formato que teñen este tipo de parámetros é: param1=valor&param2=valor&.....
 
  
−
* '''Desvantaxes:'''
+
: Por exemplo:
  
−
:* Calquera persoa pode ver os valores das variables polo que dito método non é moi seguro.
+
::<syntaxhighlight lang="text">
−
:* O usuario pode cambiar o valor de ditas variables polo que pode suceder que o sitio amose ou faga algo diferente do permitido.
+
https://exemplo.test/buscar.php?q=php&idioma=gl
−
:* O usuario pode obter información non actual se usa unha URL con datos non actualizados.
+
</syntaxhighlight>
−
:* O tamaño do que podemos enviar na URL está limitado (depende de cada navegador, pero pode estar entre 2KB-8KB)
+
 
 +
: Os datos que aparecen despois do signo '''?''' son parámetros:
 +
 
 +
::<syntaxhighlight lang="text">
 +
q=php&idioma=gl
 +
</syntaxhighlight>
 +
 
 +
: O formato xeral é:
 +
 
 +
::<syntaxhighlight lang="text">
 +
parametro1=valor1&parametro2=valor2
 +
</syntaxhighlight>
 +
 
 +
* Este mecanismo emprégase habitualmente co método HTTP '''GET'''.
 +
 
 +
* '''Características importantes dos datos enviados pola URL:'''
 +
 
 +
:* Os valores son visibles na barra de enderezos do navegador.
 +
:* A URL pode gardarse no historial, nos favoritos ou aparecer en rexistros do servidor.
 +
:* O usuario pode modificar manualmente os parámetros.
 +
:* Polo tanto, '''nunca debemos considerar fiables os datos recibidos mediante $_GET'''.
 +
:* Non debemos empregar a URL para enviar contrasinais ou outros datos sensibles.
 +
:* A lonxitude máxima dunha URL depende do navegador, do servidor web e doutros compoñentes intermedios, polo que é recomendable manter as URL razoablemente curtas.
  
 
* '''Vantaxes:'''
 
* '''Vantaxes:'''
  
−
:* A través da URL podemos pasar datos dunha páxina a outra sen necesidade de ter un formulario por medio (o veremos no exemplo seguinte).  
+
:* Permite pasar datos dunha páxina a outra sen necesidade dun formulario.
 +
:* As URL poden gardarse nos favoritos e compartirse.
 +
:* Resulta apropiado para operacións de consulta ou navegación que non modifican o estado da aplicación.
 +
 
 +
* En PHP os parámetros enviados na URL están dispoñibles no array superglobal [https://www.php.net/manual/es/reserved.variables.get.php $_GET].
 +
 
 +
: Por exemplo, para unha URL:
 +
 
 +
::<syntaxhighlight lang="text">
 +
detalle.php?pelicula=SUPERMAN
 +
</syntaxhighlight>
 +
 
 +
: podemos obter o valor mediante:
  
 +
::<syntaxhighlight lang="php">
 +
$pelicula = $_GET['pelicula'] ?? '';
 +
</syntaxhighlight>
  
 +
: Empregamos o operador '''??''' para proporcionar un valor por defecto no caso de que o parámetro non exista.
  
−
* As variables que se pasan desta forma poden ser referenciadas en PHP a través da matriz global [http://php.net/manual/es/reserved.variables.get.php $_GET['param']].
+
<br />
  
−
: Vexamos un exemplo de código:
+
=== Exemplo básico ===
  
 
'''Arquivo: UD3_paso_var_Ex1_eleccion_pelicula.php'''
 
'''Arquivo: UD3_paso_var_Ex1_eleccion_pelicula.php'''
−
::<syntaxhighlight lang="php" line enclose="div" highlight="11" >
 
−
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 
−
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
  
−
<html>
+
::<syntaxhighlight lang="php" line enclose="div">
−
    <head>
+
<!DOCTYPE html>
−
        <meta charset="UTF-8">
+
<html lang="gl">
−
        <title></title>
+
<head>
−
    </head>
+
    <meta charset="UTF-8">
−
    <body>
+
    <title>Elección dunha película</title>
−
        <?php
+
</head>
−
        printf("Mandamos un nome de película fixo na url:<a href='UD3_paso_var_Ex1_datos_pelicula.php?pelicula=SUPERMAN'>PELICULA</a>");
+
<body>
−
        ?>
+
 
−
    </body>
+
<p>
 +
    Mandamos un nome de película fixo na URL:
 +
    <a href="UD3_paso_var_Ex1_datos_pelicula.php?pelicula=SUPERMAN">PELÍCULA</a>
 +
</p>
 +
 
 +
</body>
 
</html>
 
</html>
−
</syntaxhighlight>  
+
</syntaxhighlight>
  
 +
'''Arquivo: UD3_paso_var_Ex1_datos_pelicula.php'''
  
−
'''Arquivo: UD3_paso_var_Ex1_datos_pelicula.php'''
+
::<syntaxhighlight lang="php" line enclose="div">
−
::<syntaxhighlight lang="php" line enclose="div" highlight="12" >
+
<?php
−
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+
$peliculaRecibida = $_GET['pelicula'] ?? '';
−
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
−
<html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es">
 
−
    <head>
 
−
        <meta charset="utf-8" />
 
−
        <title>Exemplos de códigos php</title>
 
−
    </head>
 
−
    <body>
 
  
−
<?php 
+
if (!is_string($peliculaRecibida)) {
 +
    $peliculaRecibida = '';
 +
}
  
−
     printf("A película pasada como parámetro na URL é: <b>%s</b>",$_GET['pelicula']);
+
$pelicula = trim($peliculaRecibida);
 +
?>
 +
<!DOCTYPE html>
 +
<html lang="gl">
 +
<head>
 +
     <meta charset="UTF-8">
 +
    <title>Datos da película</title>
 +
</head>
 +
<body>
  
 +
<p>
 +
    A película pasada como parámetro na URL é:
 +
    <strong><?= htmlspecialchars(
 +
        $pelicula,
 +
        ENT_QUOTES | ENT_SUBSTITUTE,
 +
        'UTF-8'
 +
    ) ?></strong>
 +
</p>
  
−
?>
+
</body>
−
    </body>  
 
 
</html>
 
</html>
−
</syntaxhighlight>  
+
</syntaxhighlight>
 +
 
 +
* Podedes comprobar que, se modificades o valor do parámetro '''pelicula''' na URL e cargades de novo a páxina, o novo valor chegará mediante $_GET.
  
 +
* '''IMPORTANTE:''' Que un valor apareza na URL non significa que sexa válido. O usuario pode modificalo libremente, polo que sempre debemos '''validar os datos antes de empregalos''' e '''escapar os datos cando os amosamos en HTML'''.
  
−
* Podedes comprobar como se modificades a url e poñedes outra valor, premendo a tecla 'enter' para que volva a cargar a páxina aparece o novo valor posto.
+
<br />
  
 
== Pasando caracteres especiais na URL ==
 
== Pasando caracteres especiais na URL ==
  
−
* O problema que podemos ter pasando valores desta forma, é que ditos valores teñan espazos en branco ou caracteres especiais.
+
* Os valores dunha URL non se poden construír simplemente concatenando calquera cadea. Determinados caracteres, como os espazos ou caracteres reservados, deben codificarse.
−
* Para poder pasar estes valores podemos facer uso da [http://php.net/manual/es/function.urlencode.phpfunción urlencode].
+
 
 +
* Para codificar '''un valor individual''' podemos empregar a función [https://www.php.net/manual/es/function.urlencode.php urlencode].
 +
 
 +
: Exemplo:
 +
 
 +
::<syntaxhighlight lang="php">
 +
$pelicula = urlencode('E.T. El extraterrestre');
  
−
* Para facer a función inversa: [http://php.net/manual/es/function.urldecode.php urldecode]. Pero isto non é necesario no caso de asinar o valor a unha variable na segunda páxina.
+
echo "<a href='detalle.php?pelicula=$pelicula'>PELÍCULA</a>";
 +
</syntaxhighlight>
  
−
: Vexamos unha modificación do código anterior, pasando un nome de película con espazos:
+
: Neste caso o espazo en branco codifícase como '''+'''.
 +
 
 +
* Para realizar a operación inversa existe [https://www.php.net/manual/es/function.urldecode.php urldecode].
 +
 
 +
: Normalmente non será necesario chamar manualmente a urldecode() para os parámetros recibidos mediante $_GET, xa que PHP xa realiza a decodificación da cadea de consulta.
 +
 
 +
<br />
 +
 
 +
=== Construíndo unha URL con http_build_query() ===
 +
 
 +
* Cando temos varios parámetros é preferible non construír a cadea de consulta manualmente.
 +
 
 +
* PHP dispón da función [https://www.php.net/manual/es/function.http-build-query.php http_build_query()], que xera unha cadea de consulta correctamente codificada a partir dun array.
 +
 
 +
::<syntaxhighlight lang="php">
 +
$parametros = [
 +
    'pelicula' => 'E.T. El extraterrestre',
 +
    'xenero' => 'Ciencia ficción'
 +
];
 +
 
 +
$query = http_build_query(
 +
    $parametros,
 +
    '',
 +
    '&',
 +
    PHP_QUERY_RFC3986
 +
);
 +
 
 +
$url = 'UD3_paso_var_Ex1_datos_pelicula.php?' . $query;
 +
</syntaxhighlight>
 +
 
 +
: Co valor '''PHP_QUERY_RFC3986''' os espazos codifícanse como '''%20'''.
 +
 
 +
* Se a URL vai ser inserida posteriormente dentro de HTML, tamén debemos escapar o seu valor para o contexto HTML:
 +
 
 +
::<syntaxhighlight lang="php">
 +
<a href="<?= htmlspecialchars(
 +
    $url,
 +
    ENT_QUOTES | ENT_SUBSTITUTE,
 +
    'UTF-8'
 +
) ?>">PELÍCULA</a>
 +
</syntaxhighlight>
 +
 
 +
<br />
 +
 
 +
=== Exemplo con espazos no nome da película ===
  
 
'''Arquivo: UD3_paso_var_Ex1_eleccion_pelicula.php'''
 
'''Arquivo: UD3_paso_var_Ex1_eleccion_pelicula.php'''
−
::<syntaxhighlight lang="php" line enclose="div" highlight="11" >
 
−
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 
−
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
  
−
<html>
+
::<syntaxhighlight lang="php" line enclose="div">
−
    <head>
+
<?php
−
        <meta charset="UTF-8">
+
$parametros = [
−
        <title></title>
+
    'pelicula' => 'E.T. El extraterrestre'
−
    </head>
+
];
−
    <body>
+
 
−
        <?php
+
$query = http_build_query(
−
        $pelicula=urlencode("E.T. El extraterrestre");
+
    $parametros,
−
        echo "Mandamos un nome de película fixo na url:"
+
    '',
−
                . sprintf("<a href='UD3_paso_var_Ex1_datos_pelicula.php?pelicula=%s'>PELICULA</a>",$pelicula);
+
    '&',
−
        ?>
+
    PHP_QUERY_RFC3986
−
    </body>
+
);
 +
 
 +
$url = 'UD3_paso_var_Ex1_datos_pelicula.php?' . $query;
 +
?>
 +
<!DOCTYPE html>
 +
<html lang="gl">
 +
<head>
 +
    <meta charset="UTF-8">
 +
    <title>Elección dunha película</title>
 +
</head>
 +
<body>
 +
 
 +
<p>
 +
    Mandamos un nome de película na URL:
 +
    <a href="<?= htmlspecialchars(
 +
        $url,
 +
        ENT_QUOTES | ENT_SUBSTITUTE,
 +
        'UTF-8'
 +
    ) ?>">PELÍCULA</a>
 +
</p>
 +
 
 +
</body>
 
</html>
 
</html>
−
</syntaxhighlight>  
+
</syntaxhighlight>
  
 +
'''Arquivo: UD3_paso_var_Ex1_datos_pelicula.php'''
  
−
'''Arquivo: UD3_paso_var_Ex1_datos_pelicula.php'''
+
::<syntaxhighlight lang="php" line enclose="div">
−
::<syntaxhighlight lang="php" line enclose="div" highlight="12" >
+
<?php
−
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+
$peliculaRecibida = $_GET['pelicula'] ?? '';
−
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
 
−
<html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es">
+
if (!is_string($peliculaRecibida)) {
−
    <head>
+
     $peliculaRecibida = '';
−
        <meta charset="utf-8" />
+
}
−
        <title>Exemplos de códigos php</title>
 
−
     </head>
 
−
    <body>
 
  
−
     <?php 
+
$pelicula = trim($peliculaRecibida);
 +
?>
 +
<!DOCTYPE html>
 +
<html lang="gl">
 +
<head>
 +
    <meta charset="UTF-8">
 +
     <title>Datos da película</title>
 +
</head>
 +
<body>
  
−
        // $pelicula=htmlentities($_GET['pelicula']); => Mellor con htmlspecialchars
+
<p>
−
        $pelicula = htmlspecialchars($_GET['pelicula'], ENT_QUOTES, 'UTF-8');
+
    A película pasada como parámetro na URL é:
−
        echo "A película pasada como parámetro na URL é: <b>$pelicula</b>";
+
    <strong><?= htmlspecialchars(
 +
        $pelicula,
 +
        ENT_QUOTES | ENT_SUBSTITUTE,
 +
        'UTF-8'
 +
    ) ?></strong>
 +
</p>
  
−
    ?>
+
</body>
−
    </body>  
 
 
</html>
 
</html>
−
</syntaxhighlight>  
+
</syntaxhighlight>
 +
 
 +
* A URL xerada será similar a:
 +
 
 +
::<syntaxhighlight lang="text">
 +
UD3_paso_var_Ex1_datos_pelicula.php?pelicula=E.T.%20El%20extraterrestre
 +
</syntaxhighlight>
 +
 
 +
* O usuario visualizará:
 +
 
 +
::<syntaxhighlight lang="text">
 +
E.T. El extraterrestre
 +
</syntaxhighlight>
 +
 
 +
<br />
 +
 
 +
=== urlencode(), rawurlencode() e urldecode() ===
 +
 
 +
* [https://www.php.net/manual/es/function.urlencode.php urlencode()] codifica unha cadea segundo o formato empregado habitualmente nas cadeas de consulta. Os espazos convértense en '''+'''.
 +
 
 +
* [https://www.php.net/manual/es/function.rawurlencode.php rawurlencode()] emprega unha codificación conforme á RFC 3986. Os espazos convértense en '''%20'''.
 +
 
 +
* [https://www.php.net/manual/es/function.urldecode.php urldecode()] realiza a operación inversa de urlencode().
 +
 
 +
: Exemplo:
 +
 
 +
::<syntaxhighlight lang="php">
 +
$cadea = 'Espero que isto se lea ben';
 +
 
 +
$cadeaCodificada = urlencode($cadea);
  
 +
echo $cadeaCodificada;
 +
echo '<br>';
 +
echo urldecode($cadeaCodificada);
 +
</syntaxhighlight>
  
−
: O resultado:
+
: Resultado:
−
:* Por un lado a URL: http://localhost/PhpOlaMundo/UD3_paso_var_Ex1_datos_pelicula.php?pelicula=E.T.'''+'''El'''+'''extraterrestre
 
−
:: Como vemos cambiamos o carácter espazo en branco por un +.
 
−
:* O que visualiza o usuario na páxina:  A película pasada como parámetro na URL é: '''E.T. El extraterrestre'''
 
  
 +
::<syntaxhighlight lang="text">
 +
Espero+que+isto+se+lea+ben
 +
Espero que isto se lea ben
 +
</syntaxhighlight>
  
 +
<br />
  
−
* Vexamos agora un exemplo de código de decodificación dunha cadea:
+
== Paso dun identificador para consultar datos ==
−
::<syntaxhighlight lang="php" line enclose="div" highlight="12" >
 
−
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 
−
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
−
<html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es">
 
−
    <head>
 
−
        <meta charset="utf-8" />
 
−
        <title>Exemplos de códigos php</title>
 
−
    </head>
 
−
    <body>
 
  
−
    <?php 
+
* Un uso moi habitual dos parámetros dunha URL consiste en enviar o identificador dun elemento que queremos consultar.
  
−
        $cadeaCodificada="<br/>Espero + que + isto + se lea + ben";
+
: Por exemplo, poderiamos ter os seguintes produtos:
−
        echo $cadeaCodificada;
 
−
        echo urldecode($cadeaCodificada);
 
−
       
 
−
    ?>
 
−
    </body>   
 
−
</html>
 
  
 +
::<syntaxhighlight lang="text">
 +
Código - Nome      - Descrición
 +
1      - Tomates  - Tomates da horta. Ecolóxicos...
 +
2      - Coliflor  - Coliflor da horta. Ecolóxica...
 
</syntaxhighlight>
 
</syntaxhighlight>
  
−
: Dará como resultado:
+
* Na páxina que amosa a lista de produtos poderiamos construír enlaces como:
−
::<syntaxhighlight lang="php" enclose="div" highlight="12" >
+
 
−
Espero + que + isto + se lea + ben
+
::<syntaxhighlight lang="html">
−
Espero que isto se lea ben Teño un teléfono
+
<a href="detalleProduto.php?codigo=1">Tomates</a>
 +
<a href="detalleProduto.php?codigo=2">Coliflor</a>
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
* Na páxina '''detalleProduto.php''' recibiremos o parámetro mediante $_GET.
 +
 +
* Como o código debe ser un número enteiro positivo, primeiro validaremos o dato:
  
 +
::<syntaxhighlight lang="php">
 +
$codigoRecibido = $_GET['codigo'] ?? '';
  
−
* <u>Nota:</u> Tamén é posible codificar a cadea utilizando a función [http://php.net/manual/es/function.rawurlencode.php rawurlencode].
+
if (!is_string($codigoRecibido)) {
−
: Neste caso utiliza unha codificación segundo o [http://www.faqs.org/rfcs/rfc3986.html estándar RFC3986]. Os espazo en branco son codificados con %20, por exemplo.
+
    $codigoRecibido = '';
 +
}
  
 +
$codigo = filter_var(
 +
    $codigoRecibido,
 +
    FILTER_VALIDATE_INT,
 +
    [
 +
        'options' => [
 +
            'min_range' => 1
 +
        ]
 +
    ]
 +
);
  
−
* Un uso bastante habitual é de pasar datos relacionados con datos gardados nunha base de datos, no que queiramos obter información detallada sobre un produto.
+
if ($codigo === false) {
−
: Imaxinemos o caso de que temos gardada na base de datos os nosos produtos desta forma:
+
    die('O código do produto non é válido.');
−
::<syntaxhighlight lang="java" enclose="div" highlight="" >
+
}
−
Código - Nome- Descrición - Resto de campos
 
−
0 - Tomates - Tomates da horta. Ecolóxicos,.... - url da imaxe - resto de campos
 
−
1 - Coliflor - Coliflor da horta. Ecolóxicos,.... - url da imaxe - resto de campos
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
−
* Se fago unha consulta á base de datos pode recuperar a información do código e o nome e amosalo en forma de lista sendo cada elemento da lista un enlace a unha páxina no que amosarei o resto de campos:
+
* Posteriormente poderiamos realizar a consulta á base de datos empregando '''PDO e unha consulta preparada''':
−
::<syntaxhighlight lang="java" enclose="div" highlight="" >
+
 
−
<a href='detalleProduto.php?codigo=0'>Tomates</a>
+
::<syntaxhighlight lang="php">
−
<a href='detalleProduto.php?codigo=1'>Coliflor</a>
+
$stmt = $pdo->prepare(
 +
    'SELECT codigo, nome, descricion, url_imaxe
 +
    FROM produtos
 +
    WHERE codigo = :codigo'
 +
);
 +
 
 +
$stmt->execute([
 +
    'codigo' => $codigo
 +
]);
 +
 
 +
$produto = $stmt->fetch(PDO::FETCH_ASSOC);
 +
 
 +
if ($produto === false) {
 +
    die('O produto non existe.');
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
−
: Como vemos, podemos enviar na URL o código do produto para así, cando o control chegue á páxina detalleProduto.php podemos obter có array global $_GET o código do produto e facer unha consulta á base de datos para obter a información do resto de campos do produto.
+
* Ao amosar os datos en HTML escaparemos aqueles valores que poidan conter texto:
 +
 
 +
::<syntaxhighlight lang="php">
 +
<h2><?= htmlspecialchars(
 +
    $produto['nome'],
 +
    ENT_QUOTES | ENT_SUBSTITUTE,
 +
    'UTF-8'
 +
) ?></h2>
  
 +
<p><?= htmlspecialchars(
 +
    $produto['descricion'],
 +
    ENT_QUOTES | ENT_SUBSTITUTE,
 +
    'UTF-8'
 +
) ?></p>
 +
</syntaxhighlight>
  
 +
* '''IMPORTANTE:''' Un usuario pode cambiar manualmente o valor de '''codigo''' na URL.
  
−
* '''<u>IMPORTANTE:</u>''' Se empregamos esta forma de paso de información temos que ter en conta que calquera pode cambiar o código e vería a información do produto asociado a dito código. Se non queremos que pase isto, teríamos que comprobar se a persoa que fai a solicitude ten permiso para ver o código enviado. Outra forma sería empregar un formulario en cada produto da lista [https://wiki.cifprodolfoucha.es/index.php?title=PHP_Paso_de_datos_con_formularios#Ataques_CSRF_.28Cross-Site_Request_Forgery.29 empregando un código único evitando ataques CSRF].
+
: Polo tanto, se un determinado produto ou recurso só pode ser consultado por certos usuarios, ademais de validar o identificador teremos que '''comprobar no servidor que o usuario autenticado ten permiso para acceder a ese recurso'''.
  
 +
: Cambiar GET por POST non soluciona este problema, xa que un usuario tamén pode manipular unha petición POST.
  
 
<br />
 
<br />
−
==Paso de datos con Location==
 
  
−
* Lembrar que xa vimos [https://wiki.cifprodolfoucha.es/index.php?title=PHP_Paso_de_datos_con_formularios#Redireccionamento_de_p.C3.A1xinas nun punto anterior] que podemos redireccionar e cargar outra páxina con header('Location: https://www.paxina.es'). Nesa operación poderíamos enviar datos como acabamos de explicar.
+
== Paso de datos con Location ==
 +
 
 +
* Podemos redireccionar o navegador mediante a cabeceira HTTP '''Location''':
 +
 
 +
::<syntaxhighlight lang="php">
 +
header('Location: nova_paxina.php');
 +
exit;
 +
</syntaxhighlight>
 +
 
 +
* Se queremos enviar parámetros na redirección, é preferible construír a cadea de consulta con '''http_build_query()''':
 +
 
 +
::<syntaxhighlight lang="php">
 +
$parametros = [
 +
    'nome' => 'Ana',
 +
    'idade' => 20
 +
];
 +
 
 +
$query = http_build_query(
 +
    $parametros,
 +
    '',
 +
    '&',
 +
    PHP_QUERY_RFC3986
 +
);
 +
 
 +
header('Location: nova_paxina.php?' . $query);
 +
exit;
 +
</syntaxhighlight>
 +
 
 +
* A chamada a header() debe realizarse '''antes de enviar contido ao navegador'''.
  
 +
* Despois dunha redirección é recomendable empregar '''exit;''' para evitar que continúe a execución do script.
  
 
<br />
 
<br />
−
===Exercicio Proposto===
+
 
−
: Vexamos un exemplo de validación de datos empregando un formulario.  
+
== Exercicio proposto ==
 +
 
 +
: Vexamos un exemplo de validación de datos empregando un formulario.
 +
 
 
: A situación é a seguinte:
 
: A situación é a seguinte:
−
:* Páxina alta_alumno.php no que recollemos o nome e data de nacemento dun alumno.
 
−
:: Dita páxina chama a procesar_alta.php empregando post no action.
 
−
:: En caso de que procesar_alumno.php atope problemas, amosaremos en forma de lista desordenada todos os problemas atopados.
 
−
:* Páxina procesar_alumno.php:
 
−
::  Se verifica que os datos foran enviados e que no nome ten 5 caracteres mínimo e que a lo menos se teña 10 anos de idade.
 
−
:: Cada un dos erros se garda nun array o cal debe ser enviado na url da forma apropiada (pola URL non se pode enviar arrays, teredes que convertilo a cadea, por exemplo con implode)
 
−
:: En caso de non cumprir as condicións, cargarase a páxina de alta amosando os erros que se atopen en forma de lista.
 
−
:: Se todo foi ben, amosaremos a páxina xestion_alumno.php.
 
−
:* Páxina xestion_alumno.php
 
−
:: No que amosaremos o nome e data de nacemento do alumno.
 
  
 +
:* '''Páxina alta_alumno.php'''
 +
::* Recolle o nome e a data de nacemento dun alumno.
 +
::* Envía os datos a '''procesar_alta.php''' empregando o método POST.
 +
::* O nome debe ter un mínimo de 5 caracteres.
 +
::* O alumno debe ter polo menos 10 anos.
 +
::* Se se reciben erros desde procesar_alta.php, amósanse nunha lista.
  
−
:* <u>Podedes facer que a visualización dos erros se fagan nun arquivo separado e facer o include de dito arquivo na páxina de alta_alumno.php</u>
+
:* '''Páxina procesar_alta.php'''
 +
::* Comproba que a petición foi realizada mediante POST.
 +
::* Valida no servidor o nome e a data de nacemento.
 +
::* Se hai erros, redirecciona de novo a alta_alumno.php enviando os erros na URL.
 +
::* Para construír a cadea de consulta empregarase '''http_build_query()'''.
 +
::* Se todo é correcto, redirecciona á páxina xestion_alumno.php enviando os datos necesarios.
 +
 
 +
:* '''Páxina xestion_alumno.php'''
 +
::* Amosa o nome e a data de nacemento do alumno.
 +
::* Os valores recibidos pola URL deberán tratarse como datos non fiables e escaparse antes de amosalos en HTML.
 +
 
 +
<u>Nota:</u> A validación HTML do formulario mellora a experiencia do usuario, pero '''non substitúe a validación no servidor''', xa que a petición pode ser modificada manualmente.
  
 
<br />
 
<br />
−
====Solución Exercicio Proposto====
 
−
: '''Páxina alta_alumno.php'''
 
−
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 
  
 +
=== Solución do exercicio proposto ===
 +
 +
==== Páxina alta_alumno.php ====
 +
 +
::<syntaxhighlight lang="php" enclose="div">
 
<?php
 
<?php
−
// A páxina de procesar envía na URL os posibles erros empregando implode
+
$erros = [];
−
$errores = [];
+
 
−
if (isset($_GET['errores'])) {
+
$errosRecibidos = $_GET['erros'] ?? [];
−
     $errores = explode('|', $_GET['errores']);
+
 
 +
if (is_array($errosRecibidos)) {
 +
     foreach ($errosRecibidos as $erro) {
 +
        if (is_string($erro)) {
 +
            $erros[] = $erro;
 +
        }
 +
    }
 
}
 
}
 +
 +
// Data máxima permitida: hoxe menos 10 anos.
 +
$dataMaxima = (new DateTimeImmutable('today'))
 +
    ->modify('-10 years')
 +
    ->format('Y-m-d');
 
?>
 
?>
−
 
 
<!DOCTYPE html>
 
<!DOCTYPE html>
 
<html lang="gl">
 
<html lang="gl">
 
<head>
 
<head>
 
     <meta charset="UTF-8">
 
     <meta charset="UTF-8">
−
     <title>Alta alumno</title>
+
     <title>Alta de alumno</title>
 
</head>
 
</head>
 
<body>
 
<body>
Línea 230: Línea 477:
 
<h2>Alta de alumno</h2>
 
<h2>Alta de alumno</h2>
  
−
<!-- A páxina de procesar envía na URL os posibles erros empregando implode -->
+
<?php if ($erros !== []) : ?>
−
<?php if (!empty($errores)) : ?>
+
     <ul>
−
     <ul style="color:red;">
+
         <?php foreach ($erros as $erro) : ?>
−
         <?php foreach ($errores as $e) : ?>
+
             <li><?= htmlspecialchars(
−
             <li><?= htmlspecialchars($e) ?></li>
+
                $erro,
 +
                ENT_QUOTES | ENT_SUBSTITUTE,
 +
                'UTF-8'
 +
            ) ?></li>
 
         <?php endforeach; ?>
 
         <?php endforeach; ?>
 
     </ul>
 
     </ul>
 
<?php endif; ?>
 
<?php endif; ?>
  
−
<?php
+
<form action="procesar_alta.php" method="post">
−
// Calculamos a data máxima posible: hoxe menos 10 anos
+
     <div>
−
$maxDate = date("Y-m-d", strtotime("-10 years"));
+
        <label for="nome">Nome:</label>
−
?>
+
        <input
−
 
+
            type="text"
−
<form action="procesar_alumno.php" method="post">
+
            id="nome"
−
     Nome:
+
            name="nome"
−
    <input type="text" name="nombre" minlength="5" required><br><br>
+
            minlength="5"
 +
            required
 +
        >
 +
    </div>
  
−
     Data nacemento:
+
     <div>
−
    <input type="date" name="fecha" required max="<?= $maxDate ?>"><br><br>
+
        <label for="dataNacemento">Data de nacemento:</label>
 +
        <input
 +
            type="date"
 +
            id="dataNacemento"
 +
            name="dataNacemento"
 +
            max="<?= htmlspecialchars(
 +
                $dataMaxima,
 +
                ENT_QUOTES | ENT_SUBSTITUTE,
 +
                'UTF-8'
 +
            ) ?>"
 +
            required
 +
        >
 +
    </div>
  
−
     <input type="submit" value="Enviar">
+
     <button type="submit">Enviar</button>
 
</form>
 
</form>
  
 
</body>
 
</body>
 
</html>
 
</html>
−
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
<br />
  
 +
==== Páxina procesar_alta.php ====
  
−
: '''Páxina procesar_alta.php'''
+
::<syntaxhighlight lang="php" enclose="div">
−
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 
 
<?php
 
<?php
−
// procesar_alumno.php
 
  
−
$errores = [];
+
// Esta páxina só debe procesar peticións POST.
 +
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
 +
    header('Location: alta_alumno.php');
 +
    exit;
 +
}
 +
 
 +
$erros = [];
 +
 
 +
$nomeRecibido = $_POST['nome'] ?? '';
 +
$dataRecibida = $_POST['dataNacemento'] ?? '';
 +
 
 +
// Un usuario pode manipular a petición e enviar arrays en lugar de cadeas.
 +
if (!is_string($nomeRecibido)) {
 +
    $nomeRecibido = '';
 +
}
  
−
// Comprobación individual dos campos
+
if (!is_string($dataRecibida)) {
−
if (!isset($_POST['nombre'])) {
+
     $dataRecibida = '';
−
     $errores[] = "Non se recibiu o nome.";
 
 
}
 
}
  
−
if (!isset($_POST['fecha'])) {
+
$nome = trim($nomeRecibido);
−
     $errores[] = "Non se recibiu a data de nacemento.";
+
$dataTexto = trim($dataRecibida);
 +
 
 +
/*
 +
* Validación do nome.
 +
* Neste exercicio a regra da aplicación indica que debe
 +
* ter polo menos 5 caracteres.
 +
*/
 +
if ($nome === '') {
 +
    $erros[] = 'O nome é obrigatorio.';
 +
} elseif (mb_strlen($nome) < 5) {
 +
     $erros[] = 'O nome debe ter polo menos 5 caracteres.';
 
}
 
}
  
−
// Se ambos existen, validámolos
+
/*
−
if (isset($_POST['nombre'])) {
+
* Validación da data.
−
     $nombre = trim($_POST['nombre']);
+
*
−
   
+
* O input type="date" envía normalmente a data co formato Y-m-d,
−
     if (strlen($nombre) < 5) {
+
* pero a petición pode manipularse. Por iso tamén a validamos
−
         $errores[] = "O nome debe ter polo menos 5 caracteres.";
+
* no servidor.
 +
*/
 +
$dataNacemento = false;
 +
 
 +
if ($dataTexto === '') {
 +
    $erros[] = 'Debe indicar unha data de nacemento.';
 +
} else {
 +
    try {
 +
        $dataNacemento = DateTimeImmutable::createFromFormat(
 +
            '!Y-m-d',
 +
            $dataTexto
 +
        );
 +
    } catch (ValueError) {
 +
        $dataNacemento = false;
 +
     }
 +
 
 +
    $errosData = DateTimeImmutable::getLastErrors();
 +
 
 +
    $dataValida =
 +
        $dataNacemento !== false
 +
        && (
 +
            $errosData === false
 +
            || (
 +
                $errosData['warning_count'] === 0
 +
                && $errosData['error_count'] === 0
 +
            )
 +
        )
 +
        && $dataNacemento->format('Y-m-d') === $dataTexto;
 +
 
 +
     if (!$dataValida) {
 +
         $erros[] = 'A data de nacemento non é válida.';
 +
        $dataNacemento = false;
 
     }
 
     }
 
}
 
}
  
−
if (isset($_POST['fecha'])) {
+
/*
−
    $fecha = $_POST['fecha'];
+
* Comprobamos que o alumno teña polo menos 10 anos.
−
 
+
*/
−
    if ($fecha === "") {
+
if ($dataNacemento !== false) {
−
        $errores[] = "Debe indicar unha data de nacemento.";
+
     $hoxe = new DateTimeImmutable('today');
−
     } else {
+
    $dataLimite = $hoxe->modify('-10 years');
−
        $nac = new DateTime($fecha);
 
−
        $hoxe = new DateTime();
 
−
        $idade = $hoxe->diff($nac)->y;
 
  
−
        if ($idade < 10) {
+
    if ($dataNacemento > $dataLimite) {
−
            $errores[] = "O alumno debe ter polo menos 10 anos.";
+
        $erros[] = 'O alumno debe ter polo menos 10 anos.';
−
        }
 
 
     }
 
     }
 
}
 
}
  
−
// Se hai erros volve ao formulario de alta con erros na url separados por |
+
/*
−
if (!empty($errores)) {
+
* Se hai erros volvemos ao formulario.
−
     $cadena = implode('|', $errores);
+
*
−
     header("Location: alta_alumno.php?errores=$cadena");
+
* http_build_query() permite construír correctamente a query string.
 +
* Neste caso PHP pode representar o array de erros na propia URL.
 +
*/
 +
if ($erros !== []) {
 +
     $query = http_build_query(
 +
        ['erros' => $erros],
 +
        '',
 +
        '&',
 +
        PHP_QUERY_RFC3986
 +
    );
 +
 
 +
     header('Location: alta_alumno.php?' . $query);
 
     exit;
 
     exit;
 
}
 
}
  
−
// Todo correcto
+
/*
−
header(
+
* Todo é correcto.
−
     "Location: xestion_alumno.php?nombre=" . urlencode($nombre) .
+
* Enviamos os datos á seguinte páxina empregando unha query string
−
     "&fecha=" . urlencode($fecha)
+
* construída por http_build_query().
 +
*/
 +
$query = http_build_query(
 +
     [
 +
        'nome' => $nome,
 +
        'dataNacemento' => $dataTexto
 +
    ],
 +
    '',
 +
     '&',
 +
    PHP_QUERY_RFC3986
 
);
 
);
 +
 +
header('Location: xestion_alumno.php?' . $query);
 
exit;
 
exit;
 +
</syntaxhighlight>
  
−
</syntaxhighlight>
+
<br />
  
 +
==== Páxina xestion_alumno.php ====
  
−
: '''Páxina xestion_alumno.php'''
+
::<syntaxhighlight lang="php" enclose="div">
−
::<syntaxhighlight lang="java" enclose="div" highlight="" >
 
 
<?php
 
<?php
−
// xestion_alumno.php
+
$nomeRecibido = $_GET['nome'] ?? '';
 +
$dataRecibida = $_GET['dataNacemento'] ?? '';
 +
 
 +
if (!is_string($nomeRecibido)) {
 +
    $nomeRecibido = '';
 +
}
  
−
$nombre = $_GET['nombre'] ?? 'Descoñecido';
+
if (!is_string($dataRecibida)) {
−
$fecha = $_GET['fecha'] ?? '---';
+
    $dataRecibida = '';
 +
}
 +
 
 +
$nome = trim($nomeRecibido);
 +
$dataNacemento = trim($dataRecibida);
 
?>
 
?>
−
 
 
<!DOCTYPE html>
 
<!DOCTYPE html>
 
<html lang="gl">
 
<html lang="gl">
Línea 338: Línea 683:
 
<h2>Alumno rexistrado correctamente</h2>
 
<h2>Alumno rexistrado correctamente</h2>
  
−
<p><strong>Nome:</strong> <?= htmlspecialchars($nombre) ?></p>
+
<p>
−
<p><strong>Data de nacemento:</strong> <?= htmlspecialchars($fecha) ?></p>
+
    <strong>Nome:</strong>
 +
    <?= htmlspecialchars(
 +
        $nome,
 +
        ENT_QUOTES | ENT_SUBSTITUTE,
 +
        'UTF-8'
 +
    ) ?>
 +
</p>
 +
 
 +
<p>
 +
    <strong>Data de nacemento:</strong>
 +
    <?= htmlspecialchars(
 +
        $dataNacemento,
 +
        ENT_QUOTES | ENT_SUBSTITUTE,
 +
        'UTF-8'
 +
    ) ?>
 +
</p>
 +
 
 +
<p>
 +
    <a href="alta_alumno.php">Dar de alta outro alumno</a>
 +
</p>
  
 
</body>
 
</body>
 
</html>
 
</html>
 +
</syntaxhighlight>
  
 +
<br />
 +
 +
== Ideas importantes da unidade ==
 +
 +
* Os parámetros recibidos mediante '''$_GET''' deben considerarse sempre datos non fiables.
 +
* Empregaremos '''??''' cando un parámetro pode non existir.
 +
* Validaremos os datos segundo as regras da aplicación antes de empregalos.
 +
* Para valores numéricos podemos empregar filtros como '''FILTER_VALIDATE_INT'''.
 +
* Para consultas SQL empregaremos '''PDO e consultas preparadas'''; non concatenaremos directamente datos recibidos na consulta SQL.
 +
* Para construír cadeas de consulta empregaremos preferentemente '''http_build_query()'''.
 +
* '''urlencode()''' ou '''rawurlencode()''' permiten codificar valores individuais dunha URL.
 +
* Antes de amosar texto non fiable dentro de HTML empregaremos:
 +
 +
::<syntaxhighlight lang="php">
 +
htmlspecialchars(
 +
    $dato,
 +
    ENT_QUOTES | ENT_SUBSTITUTE,
 +
    'UTF-8'
 +
);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
−
 
+
* '''ENT_QUOTES''' fai que tamén se convertan as comiñas simples e dobres.
 +
* '''ENT_SUBSTITUTE''' substitúe por un carácter de substitución as secuencias que non sexan válidas na codificación indicada, evitando problemas con texto mal codificado.
 +
* O escapado HTML e a codificación dunha URL son operacións distintas:
 +
:* '''htmlspecialchars()''' prepara texto para o contexto HTML.
 +
:* '''urlencode(), rawurlencode() e http_build_query()''' preparan datos para unha URL.
 +
* A validación realizada mediante HTML ou JavaScript non substitúe nunca a validación no servidor.
  
 
<br />
 
<br />
−
-- [[Usuario:angelfg|Ángel D. Fernández González]] -- (2025).
+
-- [[Usuario:angelfg|Ángel D. Fernández González]] -- (2026).

Revisión del 18:10 13 sep 2026

Paso de datos pola URL

  • Unha forma de pasar información dunha páxina a outra é a través dunha URL.
  • Cando unha URL leva datos despois do carácter ?, estes datos forman a denominada cadea de consulta ou query string.
Por exemplo:
https://exemplo.test/buscar.php?q=php&idioma=gl
Os datos que aparecen despois do signo ? son parámetros:
q=php&idioma=gl
O formato xeral é:
parametro1=valor1&parametro2=valor2
  • Este mecanismo emprégase habitualmente co método HTTP GET.
  • Características importantes dos datos enviados pola URL:
  • Os valores son visibles na barra de enderezos do navegador.
  • A URL pode gardarse no historial, nos favoritos ou aparecer en rexistros do servidor.
  • O usuario pode modificar manualmente os parámetros.
  • Polo tanto, nunca debemos considerar fiables os datos recibidos mediante $_GET.
  • Non debemos empregar a URL para enviar contrasinais ou outros datos sensibles.
  • A lonxitude máxima dunha URL depende do navegador, do servidor web e doutros compoñentes intermedios, polo que é recomendable manter as URL razoablemente curtas.
  • Vantaxes:
  • Permite pasar datos dunha páxina a outra sen necesidade dun formulario.
  • As URL poden gardarse nos favoritos e compartirse.
  • Resulta apropiado para operacións de consulta ou navegación que non modifican o estado da aplicación.
  • En PHP os parámetros enviados na URL están dispoñibles no array superglobal $_GET.
Por exemplo, para unha URL:
detalle.php?pelicula=SUPERMAN
podemos obter o valor mediante:
$pelicula = $_GET['pelicula'] ?? '';
Empregamos o operador ?? para proporcionar un valor por defecto no caso de que o parámetro non exista.


Exemplo básico

Arquivo: UD3_paso_var_Ex1_eleccion_pelicula.php

 1 <!DOCTYPE html>
 2 <html lang="gl">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Elección dunha película</title>
 6 </head>
 7 <body>
 8 
 9 <p>
10     Mandamos un nome de película fixo na URL:
11     <a href="UD3_paso_var_Ex1_datos_pelicula.php?pelicula=SUPERMAN">PELÍCULA</a>
12 </p>
13 
14 </body>
15 </html>

Arquivo: UD3_paso_var_Ex1_datos_pelicula.php

 1 <?php
 2 $peliculaRecibida = $_GET['pelicula'] ?? '';
 3 
 4 if (!is_string($peliculaRecibida)) {
 5     $peliculaRecibida = '';
 6 }
 7 
 8 $pelicula = trim($peliculaRecibida);
 9 ?>
10 <!DOCTYPE html>
11 <html lang="gl">
12 <head>
13     <meta charset="UTF-8">
14     <title>Datos da película</title>
15 </head>
16 <body>
17 
18 <p>
19     A película pasada como parámetro na URL é:
20     <strong><?= htmlspecialchars(
21         $pelicula,
22         ENT_QUOTES | ENT_SUBSTITUTE,
23         'UTF-8'
24     ) ?></strong>
25 </p>
26 
27 </body>
28 </html>
  • Podedes comprobar que, se modificades o valor do parámetro pelicula na URL e cargades de novo a páxina, o novo valor chegará mediante $_GET.
  • IMPORTANTE: Que un valor apareza na URL non significa que sexa válido. O usuario pode modificalo libremente, polo que sempre debemos validar os datos antes de empregalos e escapar os datos cando os amosamos en HTML.


Pasando caracteres especiais na URL

  • Os valores dunha URL non se poden construír simplemente concatenando calquera cadea. Determinados caracteres, como os espazos ou caracteres reservados, deben codificarse.
  • Para codificar un valor individual podemos empregar a función urlencode.
Exemplo:
$pelicula = urlencode('E.T. El extraterrestre');

echo "<a href='detalle.php?pelicula=$pelicula'>PELÍCULA</a>";
Neste caso o espazo en branco codifícase como +.
  • Para realizar a operación inversa existe urldecode.
Normalmente non será necesario chamar manualmente a urldecode() para os parámetros recibidos mediante $_GET, xa que PHP xa realiza a decodificación da cadea de consulta.


Construíndo unha URL con http_build_query()

  • Cando temos varios parámetros é preferible non construír a cadea de consulta manualmente.
  • PHP dispón da función http_build_query(), que xera unha cadea de consulta correctamente codificada a partir dun array.
$parametros = [
    'pelicula' => 'E.T. El extraterrestre',
    'xenero' => 'Ciencia ficción'
];

$query = http_build_query(
    $parametros,
    '',
    '&',
    PHP_QUERY_RFC3986
);

$url = 'UD3_paso_var_Ex1_datos_pelicula.php?' . $query;
Co valor PHP_QUERY_RFC3986 os espazos codifícanse como %20.
  • Se a URL vai ser inserida posteriormente dentro de HTML, tamén debemos escapar o seu valor para o contexto HTML:
<a href="<?= htmlspecialchars(
    $url,
    ENT_QUOTES | ENT_SUBSTITUTE,
    'UTF-8'
) ?>">PELÍCULA</a>


Exemplo con espazos no nome da película

Arquivo: UD3_paso_var_Ex1_eleccion_pelicula.php

 1 <?php
 2 $parametros = [
 3     'pelicula' => 'E.T. El extraterrestre'
 4 ];
 5 
 6 $query = http_build_query(
 7     $parametros,
 8     '',
 9     '&',
10     PHP_QUERY_RFC3986
11 );
12 
13 $url = 'UD3_paso_var_Ex1_datos_pelicula.php?' . $query;
14 ?>
15 <!DOCTYPE html>
16 <html lang="gl">
17 <head>
18     <meta charset="UTF-8">
19     <title>Elección dunha película</title>
20 </head>
21 <body>
22 
23 <p>
24     Mandamos un nome de película na URL:
25     <a href="<?= htmlspecialchars(
26         $url,
27         ENT_QUOTES | ENT_SUBSTITUTE,
28         'UTF-8'
29     ) ?>">PELÍCULA</a>
30 </p>
31 
32 </body>
33 </html>

Arquivo: UD3_paso_var_Ex1_datos_pelicula.php

 1 <?php
 2 $peliculaRecibida = $_GET['pelicula'] ?? '';
 3 
 4 if (!is_string($peliculaRecibida)) {
 5     $peliculaRecibida = '';
 6 }
 7 
 8 $pelicula = trim($peliculaRecibida);
 9 ?>
10 <!DOCTYPE html>
11 <html lang="gl">
12 <head>
13     <meta charset="UTF-8">
14     <title>Datos da película</title>
15 </head>
16 <body>
17 
18 <p>
19     A película pasada como parámetro na URL é:
20     <strong><?= htmlspecialchars(
21         $pelicula,
22         ENT_QUOTES | ENT_SUBSTITUTE,
23         'UTF-8'
24     ) ?></strong>
25 </p>
26 
27 </body>
28 </html>
  • A URL xerada será similar a:
UD3_paso_var_Ex1_datos_pelicula.php?pelicula=E.T.%20El%20extraterrestre
  • O usuario visualizará:
E.T. El extraterrestre


urlencode(), rawurlencode() e urldecode()

  • urlencode() codifica unha cadea segundo o formato empregado habitualmente nas cadeas de consulta. Os espazos convértense en +.
  • rawurlencode() emprega unha codificación conforme á RFC 3986. Os espazos convértense en %20.
  • urldecode() realiza a operación inversa de urlencode().
Exemplo:
$cadea = 'Espero que isto se lea ben';

$cadeaCodificada = urlencode($cadea);

echo $cadeaCodificada;
echo '<br>';
echo urldecode($cadeaCodificada);
Resultado:
Espero+que+isto+se+lea+ben
Espero que isto se lea ben


Paso dun identificador para consultar datos

  • Un uso moi habitual dos parámetros dunha URL consiste en enviar o identificador dun elemento que queremos consultar.
Por exemplo, poderiamos ter os seguintes produtos:
Código - Nome      - Descrición
1      - Tomates   - Tomates da horta. Ecolóxicos...
2      - Coliflor  - Coliflor da horta. Ecolóxica...
  • Na páxina que amosa a lista de produtos poderiamos construír enlaces como:
<a href="detalleProduto.php?codigo=1">Tomates</a>
<a href="detalleProduto.php?codigo=2">Coliflor</a>
  • Na páxina detalleProduto.php recibiremos o parámetro mediante $_GET.
  • Como o código debe ser un número enteiro positivo, primeiro validaremos o dato:
$codigoRecibido = $_GET['codigo'] ?? '';

if (!is_string($codigoRecibido)) {
    $codigoRecibido = '';
}

$codigo = filter_var(
    $codigoRecibido,
    FILTER_VALIDATE_INT,
    [
        'options' => [
            'min_range' => 1
        ]
    ]
);

if ($codigo === false) {
    die('O código do produto non é válido.');
}
  • Posteriormente poderiamos realizar a consulta á base de datos empregando PDO e unha consulta preparada:
$stmt = $pdo->prepare(
    'SELECT codigo, nome, descricion, url_imaxe
     FROM produtos
     WHERE codigo = :codigo'
);

$stmt->execute([
    'codigo' => $codigo
]);

$produto = $stmt->fetch(PDO::FETCH_ASSOC);

if ($produto === false) {
    die('O produto non existe.');
}
  • Ao amosar os datos en HTML escaparemos aqueles valores que poidan conter texto:
<h2><?= htmlspecialchars(
    $produto['nome'],
    ENT_QUOTES | ENT_SUBSTITUTE,
    'UTF-8'
) ?></h2>

<p><?= htmlspecialchars(
    $produto['descricion'],
    ENT_QUOTES | ENT_SUBSTITUTE,
    'UTF-8'
) ?></p>
  • IMPORTANTE: Un usuario pode cambiar manualmente o valor de codigo na URL.
Polo tanto, se un determinado produto ou recurso só pode ser consultado por certos usuarios, ademais de validar o identificador teremos que comprobar no servidor que o usuario autenticado ten permiso para acceder a ese recurso.
Cambiar GET por POST non soluciona este problema, xa que un usuario tamén pode manipular unha petición POST.


Paso de datos con Location

  • Podemos redireccionar o navegador mediante a cabeceira HTTP Location:
header('Location: nova_paxina.php');
exit;
  • Se queremos enviar parámetros na redirección, é preferible construír a cadea de consulta con http_build_query():
$parametros = [
    'nome' => 'Ana',
    'idade' => 20
];

$query = http_build_query(
    $parametros,
    '',
    '&',
    PHP_QUERY_RFC3986
);

header('Location: nova_paxina.php?' . $query);
exit;
  • A chamada a header() debe realizarse antes de enviar contido ao navegador.
  • Despois dunha redirección é recomendable empregar exit; para evitar que continúe a execución do script.


Exercicio proposto

Vexamos un exemplo de validación de datos empregando un formulario.
A situación é a seguinte:
  • Páxina alta_alumno.php
  • Recolle o nome e a data de nacemento dun alumno.
  • Envía os datos a procesar_alta.php empregando o método POST.
  • O nome debe ter un mínimo de 5 caracteres.
  • O alumno debe ter polo menos 10 anos.
  • Se se reciben erros desde procesar_alta.php, amósanse nunha lista.
  • Páxina procesar_alta.php
  • Comproba que a petición foi realizada mediante POST.
  • Valida no servidor o nome e a data de nacemento.
  • Se hai erros, redirecciona de novo a alta_alumno.php enviando os erros na URL.
  • Para construír a cadea de consulta empregarase http_build_query().
  • Se todo é correcto, redirecciona á páxina xestion_alumno.php enviando os datos necesarios.
  • Páxina xestion_alumno.php
  • Amosa o nome e a data de nacemento do alumno.
  • Os valores recibidos pola URL deberán tratarse como datos non fiables e escaparse antes de amosalos en HTML.

Nota: A validación HTML do formulario mellora a experiencia do usuario, pero non substitúe a validación no servidor, xa que a petición pode ser modificada manualmente.


Solución do exercicio proposto

Páxina alta_alumno.php

<?php
$erros = [];

$errosRecibidos = $_GET['erros'] ?? [];

if (is_array($errosRecibidos)) {
    foreach ($errosRecibidos as $erro) {
        if (is_string($erro)) {
            $erros[] = $erro;
        }
    }
}

// Data máxima permitida: hoxe menos 10 anos.
$dataMaxima = (new DateTimeImmutable('today'))
    ->modify('-10 years')
    ->format('Y-m-d');
?>
<!DOCTYPE html>
<html lang="gl">
<head>
    <meta charset="UTF-8">
    <title>Alta de alumno</title>
</head>
<body>

<h2>Alta de alumno</h2>

<?php if ($erros !== []) : ?>
    <ul>
        <?php foreach ($erros as $erro) : ?>
            <li><?= htmlspecialchars(
                $erro,
                ENT_QUOTES | ENT_SUBSTITUTE,
                'UTF-8'
            ) ?></li>
        <?php endforeach; ?>
    </ul>
<?php endif; ?>

<form action="procesar_alta.php" method="post">
    <div>
        <label for="nome">Nome:</label>
        <input
            type="text"
            id="nome"
            name="nome"
            minlength="5"
            required
        >
    </div>

    <div>
        <label for="dataNacemento">Data de nacemento:</label>
        <input
            type="date"
            id="dataNacemento"
            name="dataNacemento"
            max="<?= htmlspecialchars(
                $dataMaxima,
                ENT_QUOTES | ENT_SUBSTITUTE,
                'UTF-8'
            ) ?>"
            required
        >
    </div>

    <button type="submit">Enviar</button>
</form>

</body>
</html>


Páxina procesar_alta.php

<?php

// Esta páxina só debe procesar peticións POST.
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    header('Location: alta_alumno.php');
    exit;
}

$erros = [];

$nomeRecibido = $_POST['nome'] ?? '';
$dataRecibida = $_POST['dataNacemento'] ?? '';

// Un usuario pode manipular a petición e enviar arrays en lugar de cadeas.
if (!is_string($nomeRecibido)) {
    $nomeRecibido = '';
}

if (!is_string($dataRecibida)) {
    $dataRecibida = '';
}

$nome = trim($nomeRecibido);
$dataTexto = trim($dataRecibida);

/*
 * Validación do nome.
 * Neste exercicio a regra da aplicación indica que debe
 * ter polo menos 5 caracteres.
 */
if ($nome === '') {
    $erros[] = 'O nome é obrigatorio.';
} elseif (mb_strlen($nome) < 5) {
    $erros[] = 'O nome debe ter polo menos 5 caracteres.';
}

/*
 * Validación da data.
 *
 * O input type="date" envía normalmente a data co formato Y-m-d,
 * pero a petición pode manipularse. Por iso tamén a validamos
 * no servidor.
 */
$dataNacemento = false;

if ($dataTexto === '') {
    $erros[] = 'Debe indicar unha data de nacemento.';
} else {
    try {
        $dataNacemento = DateTimeImmutable::createFromFormat(
            '!Y-m-d',
            $dataTexto
        );
    } catch (ValueError) {
        $dataNacemento = false;
    }

    $errosData = DateTimeImmutable::getLastErrors();

    $dataValida =
        $dataNacemento !== false
        && (
            $errosData === false
            || (
                $errosData['warning_count'] === 0
                && $errosData['error_count'] === 0
            )
        )
        && $dataNacemento->format('Y-m-d') === $dataTexto;

    if (!$dataValida) {
        $erros[] = 'A data de nacemento non é válida.';
        $dataNacemento = false;
    }
}

/*
 * Comprobamos que o alumno teña polo menos 10 anos.
 */
if ($dataNacemento !== false) {
    $hoxe = new DateTimeImmutable('today');
    $dataLimite = $hoxe->modify('-10 years');

    if ($dataNacemento > $dataLimite) {
        $erros[] = 'O alumno debe ter polo menos 10 anos.';
    }
}

/*
 * Se hai erros volvemos ao formulario.
 *
 * http_build_query() permite construír correctamente a query string.
 * Neste caso PHP pode representar o array de erros na propia URL.
 */
if ($erros !== []) {
    $query = http_build_query(
        ['erros' => $erros],
        '',
        '&',
        PHP_QUERY_RFC3986
    );

    header('Location: alta_alumno.php?' . $query);
    exit;
}

/*
 * Todo é correcto.
 * Enviamos os datos á seguinte páxina empregando unha query string
 * construída por http_build_query().
 */
$query = http_build_query(
    [
        'nome' => $nome,
        'dataNacemento' => $dataTexto
    ],
    '',
    '&',
    PHP_QUERY_RFC3986
);

header('Location: xestion_alumno.php?' . $query);
exit;


Páxina xestion_alumno.php

<?php
$nomeRecibido = $_GET['nome'] ?? '';
$dataRecibida = $_GET['dataNacemento'] ?? '';

if (!is_string($nomeRecibido)) {
    $nomeRecibido = '';
}

if (!is_string($dataRecibida)) {
    $dataRecibida = '';
}

$nome = trim($nomeRecibido);
$dataNacemento = trim($dataRecibida);
?>
<!DOCTYPE html>
<html lang="gl">
<head>
    <meta charset="UTF-8">
    <title>Xestión do alumno</title>
</head>
<body>

<h2>Alumno rexistrado correctamente</h2>

<p>
    <strong>Nome:</strong>
    <?= htmlspecialchars(
        $nome,
        ENT_QUOTES | ENT_SUBSTITUTE,
        'UTF-8'
    ) ?>
</p>

<p>
    <strong>Data de nacemento:</strong>
    <?= htmlspecialchars(
        $dataNacemento,
        ENT_QUOTES | ENT_SUBSTITUTE,
        'UTF-8'
    ) ?>
</p>

<p>
    <a href="alta_alumno.php">Dar de alta outro alumno</a>
</p>

</body>
</html>


Ideas importantes da unidade

  • Os parámetros recibidos mediante $_GET deben considerarse sempre datos non fiables.
  • Empregaremos ?? cando un parámetro pode non existir.
  • Validaremos os datos segundo as regras da aplicación antes de empregalos.
  • Para valores numéricos podemos empregar filtros como FILTER_VALIDATE_INT.
  • Para consultas SQL empregaremos PDO e consultas preparadas; non concatenaremos directamente datos recibidos na consulta SQL.
  • Para construír cadeas de consulta empregaremos preferentemente http_build_query().
  • urlencode() ou rawurlencode() permiten codificar valores individuais dunha URL.
  • Antes de amosar texto non fiable dentro de HTML empregaremos:
htmlspecialchars(
    $dato,
    ENT_QUOTES | ENT_SUBSTITUTE,
    'UTF-8'
);
  • ENT_QUOTES fai que tamén se convertan as comiñas simples e dobres.
  • ENT_SUBSTITUTE substitúe por un carácter de substitución as secuencias que non sexan válidas na codificación indicada, evitando problemas con texto mal codificado.
  • O escapado HTML e a codificación dunha URL son operacións distintas:
  • htmlspecialchars() prepara texto para o contexto HTML.
  • urlencode(), rawurlencode() e http_build_query() preparan datos para unha URL.
  • A validación realizada mediante HTML ou JavaScript non substitúe nunca a validación no servidor.


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