PHP Paso de datos na URL

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

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