Diferencia entre revisiones de «PHP Paso de datos con formularios»

De MediaWiki
Ir a la navegación Ir a la búsqueda
Línea 1: Línea 1:
 
== Introdución ==
 
== Introdución ==
  
−
* Sabemos que a través da etiqueta <form> podemos enviar datos dunha páxina a outra.
+
* Cando programamos pode darse o caso de que teñamos código (en forma de funcións, variables, constantes, clases ou bloques de código) que teñamos que utilizar en moitas páxinas distintas.
−
: Os principais elementos html que poden enviar información dentro dun formulario son [https://www.w3schools.com/html/html_form_elements.asp os indicados neste enlace].
 
  
 +
* Nestes casos é conveniente ter o código gardado nun arquivo separado e poder incorporalo cando o necesitemos.
  
−
* Dentro da etiqueta form temos:
+
* En PHP podemos facelo coas construcións da linguaxe: '''include''', '''include_once''', '''require''' e '''require_once'''.
−
:* O atributo '''method''' que pode tomar os valores '''get''' ou '''post'''.
 
−
:* O atributo '''action''' que indica a páxina que ten que procesar os datos enviados polo formulario. Aquí poñeremos unha páxina php e moitas veces será a mesma páxina que ten o formulario, polo que podemos empregar como action: $_SERVER['PHP_SELF'] da forma:
 
−
:::<syntaxhighlight lang="php" line enclose="div" highlight="1" >
 
−
<form name="form1" action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST">
 
−
 
 
−
</form>
 
−
</syntaxhighlight>
 
−
 
 
−
 
 
−
 
 
−
* <u>Nota:</u> Para pasar datos dunha páxina a outra tamén podemos empregar formularios con campos ocultos (hidden).
 
−
 
 
−
== Método GET ==
 
−
 
 
−
* Neste caso os datos son enviados na URL e pasan a páxina indicada polo etiqueta '''action''' do formulario no seguinte formato: http://paxinadestino.php?param1=valor&param2=valor&.....
 
−
* 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
 
−
: 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 [http://php.net/manual/es/reserved.variables.get.php $_GET['param']].
 
  
 +
<br />
 +
== include ==
  
−
* Vexamos agora un exemplo <u>utilizando un formulario</u>:
+
* <u>Sintaxe:</u>
  
−
'''Arquivo: UD2_Form_Ex1_eleccion_pelicula.php'''
+
::<syntaxhighlight lang="php" enclose="div">
−
::<syntaxhighlight lang="php" line enclose="div" highlight="27" >
+
include '[path/]arquivo.php';
−
<!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>Formulario</title>
 
−
        <style>
 
−
            .formularios{
 
−
                width: 30%;
 
−
                margin: 0px auto;
 
−
            }
 
−
            .etiqueta{
 
−
                float: left;
 
−
                width: 190px;
 
−
            }
 
−
            .botonesformularios{
 
−
                width: 50%;
 
−
                margin: 30px auto;
 
−
                text-align: center;
 
−
            }
 
−
            select {
 
−
                width:50%;
 
−
            }
 
−
        </style>
 
−
    </head>
 
−
    <body>
 
−
        <form id="frmPelicula" class="formularios" method="get" action="UD2_Form_Ex1_datos_pelicula.php">
 
−
            <div>   
 
−
                <div class='etiqueta'>Película preferida:</div>
 
−
                <select name="lstPelicula"><option>E.T. El extraterrestre</option><option>Supermán</option></select>
 
−
            </div>               
 
−
            <div>
 
−
                <div class='etiqueta'>Xénero preferido:</div>
 
−
                <select name="lstXenero"><option>Acción</option><option>Ciencia ficción</option></select>
 
−
            </div>               
 
−
            <div class="botonesformularios">
 
−
                <input type='submit' value="ENVIAR" />
 
−
            </div>
 
−
        </form>
 
−
 
 
−
    </body>   
 
−
</html>
 
−
</php>
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
−
:* Fixarse que enviamos os datos utilizando o '''método get'''.
+
* A sentenza '''include''' inclúe e avalía o arquivo especificado.
  
−
'''Arquivo: UD2_Form_Ex1_datos_pelicula.php'''
+
* O camiño pode ser absoluto ou relativo. Para evitar problemas coa resolución de rutas é recomendable construír a ruta tomando como referencia o directorio do arquivo PHP actual mediante a constante máxica '''__DIR__'''.
−
::<syntaxhighlight lang="php" line enclose="div" highlight="13,14" >
 
−
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 
−
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
  
−
<html>
+
: Por exemplo:
−
    <head>
 
−
        <meta charset="UTF-8">
 
−
        <title></title>
 
−
    </head>
 
−
    <body>
 
−
        <?php
 
−
        echo 'Os datos que escolliches son:<br/><br/>';
 
−
       
 
−
        $pelicula = $_GET['lstPelicula'];
 
−
        $xenero = $_GET['lstXenero'];
 
  
−
        printf("PELICULA:%s<br/>XÉNERO:%s",$pelicula,$xenero);
+
::<syntaxhighlight lang="php" enclose="div">
−
        ?>
+
include __DIR__ . '/utilidades/arquivo.php';
−
       
 
−
    </body>
 
−
</html>
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
* Antigamente empregábase con frecuencia a extensión ''.inc.php'' para este tipo de arquivos, pero actualmente podemos empregar directamente a extensión ''.php''.
  
 +
* O código PHP do arquivo incluído debe atoparse entre etiquetas PHP.
  
−
* <u>NOTA:</u> Se queredes visualizar o conxunto de valores que temos en $_GET podedes empregar [https://www.php.net/manual/es/function.var-dump.php a función var_dump] da forma: var_dump($_GET);
+
: Se o arquivo contén unicamente código PHP, é recomendable empregar a etiqueta de apertura '''<?php''' e '''omitir a etiqueta de peche ?>''' ao final do arquivo.
  
−
== Método POST ==
+
: Desta forma evitamos que espazos ou saltos de liña situados accidentalmente despois da etiqueta de peche produzan unha saída non desexada.
  
−
* No método post de envío de datos, os mesmos van 'dentro' da páxina web, no corpo do formulario, e polo tanto non son visibles para o usuario.
+
* Vexamos un exemplo:
  
−
* 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.
+
: '''Arquivo: FuncionsExternas.php'''
−
: Podemos cambiar dito límite:
 
−
::* Modificando a directiva [http://php.net/manual/es/ini.core.php#ini.post-max-size 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).
 
  
−
: <u>Nota:</u> No caso de subir arquivos tamén pode ser necesario modificar a [http://php.net/manual/es/ini.core.php#ini.upload-max-filesize directiva upload_max_filesize] do arquivo php.ini
+
::<syntaxhighlight lang="php" line enclose="div">
−
: Podedes ver [http://angelfernandezgonzalez.blogspot.com.es/2015/10/subir-archivos-de-mas-de-8mb-en.html neste enlace] como aumentar o tamaño dos arquivos subidos nun aloxamento compartido.
+
<?php
  
−
   
+
/**
−
* 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.post.php $_POST['param']].
+
  * Crea un array cun número específico de elementos inicializados a null.
 +
*
 +
* @param int $numElementos Número de elementos que terá o array.
 +
*
 +
* @return array Array co número de elementos indicado, todos con valor null.
 +
*/
 +
function crearArray(int $numElementos): array
 +
{
 +
    $array = [];
  
 +
    for ($cont = 0; $cont < $numElementos; $cont++) {
 +
        $array[$cont] = null;
 +
    }
  
−
* Modificamos o exemplo anterior para que envíe os datos con POST:
+
     return $array;
−
 
+
}
−
'''Arquivo: UD2_Form_Ex2_eleccion_pelicula.php'''
 
−
::<syntaxhighlight lang="php" line enclose="div" highlight="27" >
 
−
<!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>Formulario</title>
 
−
        <style>
 
−
            .formularios{
 
−
                width: 30%;
 
−
                margin: 0px auto;
 
−
            }
 
−
            .etiqueta{
 
−
                float: left;
 
−
                width: 190px;
 
−
            }
 
−
            .botonesformularios{
 
−
                width: 50%;
 
−
                margin: 30px auto;
 
−
                text-align: center;
 
−
            }
 
−
            select {
 
−
                width:50%;
 
−
            }
 
−
        </style>
 
−
    </head>
 
−
    <body>
 
−
        <form id="frmPelicula" class="formularios" method="post" action="UD2_Form_Ex2_datos_pelicula.php">
 
−
            <div>   
 
−
                <div class='etiqueta'>Película preferida:</div>
 
−
                <select name="lstPelicula"><option>E.T. El extraterrestre</option><option>Supermán</option></select>
 
−
            </div>               
 
−
            <div>
 
−
                <div class='etiqueta'>Xénero preferido:</div>
 
−
                <select name="lstXenero"><option>Acción</option><option>Ciencia ficción</option></select>
 
−
            </div>               
 
−
            <div class="botonesformularios">
 
−
                <input type='submit' value="ENVIAR" />
 
−
            </div>
 
−
        </form>
 
−
 
 
−
    </body>   
 
−
</html>
 
−
</php>
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
−
:* Fixarse que enviamos os datos utilizando o '''método post'''.
+
: '''Arquivo: ReutilizandoCodigo.php'''
  
−
'''Arquivo: UD2_Form_Ex2_datos_pelicula.php'''
+
::<syntaxhighlight lang="php" line enclose="div">
−
::<syntaxhighlight lang="php" line enclose="div" highlight="13,14" >
+
<!DOCTYPE html>
−
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+
<html lang="gl">
−
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
<head>
 +
    <meta charset="UTF-8">
 +
     <title>Exemplos de código PHP</title>
 +
</head>
 +
<body>
 +
<?php
 +
include __DIR__ . '/FuncionsExternas.php';
  
−
<html>
+
$datos = crearArray(10);
−
    <head>
 
−
        <meta charset="UTF-8">
 
−
        <title></title>
 
−
    </head>
 
−
    <body>
 
−
        <?php
 
−
        echo 'Os datos que escolliches son:<br/><br/>';
 
−
       
 
−
        $pelicula = $_POST['lstPelicula'];
 
−
        $xenero = $_POST['lstXenero'];
 
  
−
        printf("PELICULA:%s<br/>XÉNERO:%s",$pelicula,$xenero);
+
foreach ($datos as $clave => $dato) {
−
        ?>
+
    printf(
−
       
+
        "Clave:%d - Valor:%s<br>",
−
    </body>
+
        $clave,
 +
        $dato === null ? 'Sen dato' : $dato
 +
    );
 +
}
 +
?>
 +
</body>
 
</html>
 
</html>
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
* As funcións e clases definidas nun arquivo incluído teñen ámbito global.
  
 +
* No caso das variables, o arquivo incluído herda o ámbito do punto no que se realiza a inclusión.
  
 +
: Por exemplo, se facemos un '''include''' dentro dunha función, as variables definidas no arquivo incluído pertencerán ao ámbito desa función.
  
−
* <u>NOTA:</u> Se queredes visualizar o conxunto de valores que temos en $_POST podedes empregar [https://www.php.net/manual/es/function.var-dump.php a función var_dump] da forma: var_dump($_POST);
+
* Cando fagamos unha aplicación con acceso a base de datos teremos que gardar información sensible, como datos de conexión.
−
 
 
−
== 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 [https://wiki.cifprodolfoucha.es/index.php?title=PHP_Constantes_e_variables._%C3%81mbito.#Comprobaci.C3.B3n_de_definici.C3.B3n_e_asignaci.C3.B3n as funcións que comproban se un campo ten datos] e [https://wiki.cifprodolfoucha.es/index.php?title=PHP_Constantes_e_variables._%C3%81mbito.#Comprobaci.C3.B3n_do_tipo_de_dato as funcións que comproban o tipo de dato dunha variable].
 
−
 
 
−
 
 
−
 
 
−
* O primeiro que teríamos que comprobar é se o formulario recibe datos. Para iso utilizaremos as funcións vistas [https://wiki.cifprodolfoucha.es/index.php?title=PHP_Constantes_e_variables._%C3%81mbito.#Comprobaci.C3.B3n_de_definici.C3.B3n_e_asignaci.C3.B3n nunha sección anterior da wiki].
 
−
 
 
−
::<syntaxhighlight lang="php" line enclose="div" highlight="" >
 
  
−
if (empty($_GET)) die('Non se enviaron datos');  // Isto é válido para action=get no formulario
+
: É recomendable gardar este tipo de información nun arquivo situado '''fóra''' da ruta pública do servidor web.
−
if (!isset($_POST["enviar"]))  die('Non se enviaron datos');  // Isto é válido para action=post no formulario, sendo enviar o nome do botón que xera o action do formulario
 
  
−
</syntaxhighlight>
+
:: Imaxinemos que o servidor web publica por defecto o cartafol:
  
−
<u>Nota:</u> A [http://www.w3schools.com/php/func_misc_die.asp función die] ao igual que a [http://php.net/manual/es/function.exit.php función exit] finaliza a páxina php.
+
::<syntaxhighlight lang="text">
−
 
+
/var/www/html
−
: 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.
 
−
 
 
−
::<syntaxhighlight lang="php" line enclose="div" highlight="" >
 
−
if (empty($_POST['txtNome'])) echo('Campo nome non ten datos');
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
−
* <u>'''IMPORTANTE:'''</u> 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.
+
:: Poderiamos gardar a configuración, por exemplo, en:
−
 
 
−
: Facendo o cast podemos saber se é un número ou non da seguinte forma:
 
  
−
::<syntaxhighlight lang="php" line enclose="div" highlight="" >
+
::<syntaxhighlight lang="text">
−
if (ctype_digit($_POST['txtIdade'])){
+
/var/www/configuracions/informacionbd.php
−
    $idade = (int)$_POST['txtIdade'];
 
−
}
 
−
else {
 
−
    echo 'Non é numérico integer';
 
−
}
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
−
: Usamos a [http://php.net/manual/es/function.ctype-digit.php función ctype_digit] para comprobar se temos díxitos numéricos no dato enviado.
+
:: Desta forma, coa configuración habitual do servidor web, ese arquivo non poderá solicitarse directamente mediante unha URL.
−
: 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 ==
 
−
 
 
−
* '''No cliente:'''
 
−
: * Para validar os campos podemos empregar javascript e algún dos atributos que teñen as etiquetas HTML.
 
−
:: Calquera das dúas formas son vulnerables de que un usuario salte as regras de validación, polo que suele ser necesario facer a validación no servidor por seguridade (ver máis adiante métodos de ataque por formularios).
 
−
:: A nivel de HTML temos as seguintes propiedaes:
 
−
::* '''required''': Impide campos baleiros.
 
−
::* '''Lonxitude de cadeas''' con atributos coma maxlength, max, min...
 
−
::* '''Atributo type''' para establecer o tipo de dato que vai levar a caixa de texto: mail, text, number, date ...
 
−
::* '''Atributo accept''' para os input de tipo File que van subir un arquivo ao servidor. Con este atributo podemos especificar o tipo de arquivos que está permitido subir (exemplo accept=".pdf"),
 
−
 
 
−
 
 
−
 
 
−
 
 
  
 
<br />
 
<br />
−
* '''No servidor:'''
+
== include_once ==
−
 
 
−
* 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 que fai dita validación chámase [http://php.net/manual/es/function.filter-var.php función filter_var()]
 
−
 
 
−
: 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 [http://php.net/manual/es/function.addslashes.php 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. A empregar en vez FILTER_SANITIZE_STRING.
 
−
:: Normalmente con filter_var($valor,FILTER_SANITIZE_FULL_SPECIAL_CHARS, '''FILTER_FLAG_NO_ENCODE_QUOTES''')
 
−
 
 
−
:* FILTER_SANITIZE_STRING => '''Deprecated''' => vai ser quitada. 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 &amp;
 
−
:: 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
 
−
::<syntaxhighlight lang="php" line enclose="div" highlight="" >
 
−
<?php 
 
−
    $var = 123; 
 
−
    echo filter_var($var, FILTER_VALIDATE_INT); 
 
−
?>
 
−
</syntaxhighlight>
 
−
:: Devolve o número xa que é un enteiro.
 
−
 
 
−
* Validando un número enteiro
 
−
::<syntaxhighlight lang="php" line enclose="div" highlight="" >
 
−
<?php 
 
−
    $var = -2.343; 
 
−
    if(filter_var($var, FILTER_VALIDATE_INT) === false){ 
 
−
        echo 'Valor incorrecto'; 
 
−
    }else{ 
 
−
        echo 'Valor correcto'; 
 
−
    } 
 
−
?>
 
−
</syntaxhighlight>
 
−
:: Devolve 'Valor incorrecto' xa que non é un enteiro e polo tanto a función devolve false.
 
−
 
 
−
* Validando un número enteiro
 
−
::<syntaxhighlight lang="php" line enclose="div" highlight="" >
 
−
<?php 
 
−
    $var = -2; 
 
−
    if(filter_var($var, FILTER_VALIDATE_INT) === false){ 
 
−
        echo 'Valor incorrecto'; 
 
−
    }else{ 
 
−
        echo 'Valor correcto'; 
 
−
    } 
 
−
?>
 
−
</syntaxhighlight>
 
−
:: Devolve 'Valor correcto'.
 
−
 
 
−
 
 
−
* Validando un número flotante
 
−
::<syntaxhighlight lang="php" line enclose="div" highlight="2,3" >
 
−
<?php
 
−
    $var = '-1.45'; 
 
−
    if(filter_var($var, FILTER_VALIDATE_FLOAT) === false){ 
 
−
        echo 'Valor incorrecto'; 
 
−
    }else{ 
 
−
        echo 'Valor correcto'; 
 
−
    } 
 
−
?>
 
−
</syntaxhighlight>
 
−
:: Devolve 'Valor correcto'.
 
−
 
 
−
 
 
−
* Validando un email
 
−
::<syntaxhighlight lang="php" line enclose="div" highlight="" >
 
−
<?php 
 
−
    $var = 'casa@hotmail'; 
 
−
    if (!filter_var($var,FILTER_VALIDATE_EMAIL)){
 
−
        echo "Valor incorrecto";
 
−
    }else{ 
 
−
        echo 'Valor correcto'; 
 
−
    } 
 
−
?>
 
−
</syntaxhighlight>
 
−
:: 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.
 
−
::<syntaxhighlight lang="php" line enclose="div" highlight="3" >
 
−
<?php 
 
−
    $var = '<isto non está permitido> Isto si aparece'; 
 
−
    echo filter_var($var, FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_NO_ENCODE_QUOTES);
 
−
</syntaxhighlight>
 
−
:: Devolve 'Isto si aparece'.
 
−
 
 
−
 
 
−
* Corrixindo un número flotante.
 
−
::<syntaxhighlight lang="php" line enclose="div" highlight="" >
 
−
<?php
 
−
$number="53.3pp";
 
−
 
 
−
var_dump(filter_var($number, FILTER_SANITIZE_NUMBER_FLOAT,
 
−
FILTER_FLAG_ALLOW_FRACTION));  // Este flag fai que o caracter 'punto' sexa válido (separador de decimais)
 
−
?>
 
−
</syntaxhighlight>
 
−
:: Devolve '53.3'.
 
−
 
 
−
=== Establecendo criterios ===
 
−
 
 
−
* Podemos indicar que rango de valores son aceptables polo filtro.
 
−
 
 
−
* Validando un número enteiro dentro dun rango
 
−
::<syntaxhighlight lang="php" line enclose="div" highlight="5,6" >
 
−
<?php 
 
−
    $var = -200; 
 
−
    $opciones = array(
 
−
        'options' => array(
 
−
        'min_range' => 10,
 
−
        'max_range' => 100
 
−
    ));
 
−
     
 
−
    if(filter_var($var, FILTER_VALIDATE_INT, $opciones) === false){ 
 
−
        echo 'Valor incorrecto'; 
 
−
    }else{ 
 
−
        echo 'Valor correcto'; 
 
−
    } 
 
−
?>
 
−
</syntaxhighlight>
 
−
:: Devolve 'Valor incorrecto'
 
−
 
 
−
 
 
−
* Podemos facer unha modificación para que en caso incorrecto devolva sempre un valor 'por defecto':
 
−
::<syntaxhighlight lang="php" line enclose="div" highlight="5" >
 
−
<?php 
 
−
    $var = -200; 
 
−
    $opciones = array(
 
−
        'options' => array(
 
−
        'default' => 3, // valor a retornar se o filtro faiaa
 
−
        'min_range' => 10,
 
−
        'max_range' => 100
 
−
    ));
 
−
     
 
−
    $var = filter_var($var, FILTER_VALIDATE_INT, $opciones);
 
−
    echo $var;
 
−
 
 
−
?>
 
−
</syntaxhighlight>
 
−
:: 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.
 
−
::<syntaxhighlight lang="php" line enclose="div" highlight="2,5" >
 
−
<?php 
 
−
    $var = '1,23'; 
 
−
    $opciones = array(
 
−
        'options' => array(
 
−
        'decimal' => ','
 
−
    ));
 
−
     
 
−
    if(filter_var($var, FILTER_VALIDATE_FLOAT, $opciones) === false){ 
 
−
        echo 'Valor incorrecto'; 
 
−
    }else{ 
 
−
        echo 'Valor correcto'; 
 
−
    } 
 
−
?>   
 
−
 
 
−
</syntaxhighlight>
 
−
:: Devolve 'Valor correcto'
 
−
 
 
−
 
 
−
*<u>Nota:</u> Podemos facer uso da [http://php.net/manual/en/function.filter-input.php función filter_input] que permite obter un dato dun formulario e validar ao mesmo tempo.
 
−
 
 
−
== 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'
 
−
::<syntaxhighlight lang="php" line enclose="div" highlight="2,5" >
 
−
<?php
 
−
            $nome=$_POST['usuarios'];
 
−
            $password=$_POST['password'];
 
−
                     
 
−
            printf("select count(*) from USUARIOS where nome='%s' and password='%s'",$nome,$password);
 
−
?>
 
−
</syntaxhighlight>
 
−
: 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 <b>nome='angel'</b> and <b>password='12345678'</b>
 
−
 
 
−
* Agora <u>modifiquemos o campo password</u> 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.
 
−
 
 
−
<u>Nota:</u> 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:
 
−
 
 
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
 
−
DELIMITER //
 
−
CREATE PROCEDURE country_hos
 
−
(IN log VARCHAR(20),IN pass VARCHAR(30))
 
−
BEGIN
 
−
  SELECT count(*) FROM USUARIOS
 
−
  WHERE login = log and password = pass;
 
−
END //
 
−
DELIMITER ;
 
−
</syntaxhighlight>
 
−
 
 
−
: 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 que temos é a de utilizar os [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Paso_de_datos_con_formularios#Filtros_para_a_correcci.C3.B3n filtros de corrección vistos anteriormente] como por exemplo FILTER_SANITIZE_FULL_SPECIAL_CHARS que fai un escape dos caracteres como as cominllas simples ou dobres.
 
−
 
 
−
* Outra opción é a de utilizar funcións que provea o S.X.B.D. utilizado.
 
−
: No caso de mysql temos a [http://php.net/manual/es/mysqli.real-escape-string.php función mysqli_real_escape_string]. O veremos cando cheguemos á sección de acceso a datos.
 
−
 
 
−
 
 
−
 
 
−
* Tamén podemos empregar a [http://php.net/manual/es/mysqli.prepare.php función mysqli::prepare] como [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Operaci%C3%B3ns_BD_Mysql#Optimizaci.C3.B3n:_Sentenzas_Prepared veremos posteriormente en acceso a datos].
 
−
 
 
−
=== Cross-Site Scripting (XSS) ===
 
−
 
 
−
* Máis información [https://es.wikipedia.org/wiki/Cross-site_scripting neste enlace].
 
−
 
 
−
 
 
−
* 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 <u>vixiar os datos que VISUALICEMOS na páxina</u>.
 
−
 
 
  
−
: Un exemplo sería se introducimos dentro dun text-area este código:
+
* <u>Sintaxe:</u>
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
 
−
<script>window.location="http://www.google.es";</script>
 
−
</syntaxhighlight>  
 
  
−
: O que vai pasar é que o navegador cando cargue a páxina vai cargar a páxina de google indicada no código javascript.
+
::<syntaxhighlight lang="php" enclose="div">
−
: Fixarse no perigo que supón xa que un atacante pode levar a un usuario a outro sitio web diferente.
+
include_once '[path/]arquivo.php';
−
 
 
−
* 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...
 
−
 
 
−
<u>Importante:</u> 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:
 
−
 
 
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
 
−
<form method="post" action="<?php echo $_SERVER['PHP_SELF']); ?>" name="formulario_perfumes">
 
−
 
 
−
......
 
−
 
 
−
</form>
 
−
</syntaxhighlight>
 
−
 
 
−
 
 
−
==== Solucións ao ataque Cross-Site Scripting (XSS) ====
 
−
 
 
−
 
 
−
* Igual que no caso anterior podemos utilizar a [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Paso_de_datos_con_formularios#Funci.C3.B3n_para_validar_.2F_corrixir_campos función filter_var] cos filtros FILTER_SANITIZE_MAGIC_QUOTES ou FILTER_SANITIZE_FULL_SPECIAL_CHARS para eliminar dita posibilidade.
 
−
 
 
−
* En PHP podemos facer uso das seguintes funcións:
 
−
:* [http://php.net/manual/es/function.strip-tags.php Función strip_tags]: Dita función fai o mesmo que FILTER_SANITIZE_FULL_SPECIAL_CHARS e ademais podemos indicar cales etiquetas son permitidas.
 
−
:* [http://php.net/manual/es/function.htmlentities.php 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)
 
−
:* [https://www.php.net/manual/es/function.htmlspecialchars.php htmlspecialchars]: Moi parecida á anterior, ten a mesma función pero é máis lixeira a nivel de carga de CPU xa que elimina soamente aqueles caracteres que poidan ser empregados para un ataques XSS). Normalmente a empregaremos con estes argumentos: $novoDato = htmlspecialchars($dato, ENT_QUOTES, 'UTF-8');  
 
−
:: É a opción a empregar cando queramos visualizar datos que proveñan da base de datos ou dun campo de formulario.
 
−
 
 
−
 
 
−
: No caso do formulario poderíamos poñer:
 
−
<form method="post" action="<?php echo htmlspecialchars($_SERVER['PHP_SELF'], ENT_QUOTES, 'UTF-8') ?>" name="formulario_perfumes">
 
−
 
 
−
......
 
−
 
 
−
</form>
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
* '''include_once''' ten o mesmo comportamento que '''include''', pero PHP comproba se o arquivo xa foi incluído previamente. Se xa foi incluído, non o volve procesar.
  
−
<br />
+
* Isto é especialmente útil cando o arquivo define funcións, clases ou constantes, xa que incluílo máis dunha vez podería provocar erros por declaracións duplicadas.
−
 
 
−
===Ataques CSRF (Cross-Site Request Forgery)===
 
−
 
 
−
* O veremos [https://wiki.cifprodolfoucha.es/index.php?title=PHP_Sesi%C3%B3ns#Ataques_CSRF_.28Cross-Site_Request_Forgery.29 cando vexamos as variables de sesión na UD4].
 
−
 
 
  
 +
* Debemos escoller entre '''include''' e '''include_once''' en función de se queremos permitir ou non que o mesmo arquivo sexa procesado máis dunha vez.
  
−
<br />
+
* Pode darse o caso, por exemplo, cando facemos inclusións condicionais dentro dun '''if''', de que un arquivo xa fose cargado previamente.
−
===Normas xerais===
 
−
 
 
−
 
 
−
 
 
−
* Como normas xerais:
 
−
:* Nos formularios sempre debemos empregar a técnica que evite os ataques CSRF (será explicada na sección de sesión).
 
−
:* Empregaremos a función htmlentities para amosar datos ao usuario que veñan de formularios ou da base de datos.
 
−
:* Empregaremos a función mysqli_real_escape_string sobre os datos que van ser gardados na base de datos. O veremos cando cheguemos á sección de acceso a datos.
 
−
:* Empregaremos filtros de validación para chequear o tipo e formato de datos que veñan dun formulario.
 
−
:* Empregaremos filtros de corrección cando queramos gardar na base de datos campos de texto no que queramos eliminar previamente os caracteres non permitidos.
 
  
 +
* Os arquivos incluídos tamén poden utilizarse para gardar elementos comúns a varias páxinas web, como unha cabeceira, un menú ou un pé de páxina.
  
 +
: Desta forma, se necesitamos modificar un elemento común, soamente teremos que facelo nun único arquivo.
  
 +
* En PHP existe outra forma de organizar os elementos comúns empregando un modelo ou patrón MVC.
  
 +
: Podedes consultalo [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Conceptos_b%C3%A1sicos_Modelo-Vista-Controlador#Opci.C3.B3n_2 neste enlace da WIKI].
  
 
<br />
 
<br />
 +
== require ==
  
−
== Obtendo variables de formularios (post/get) e filtrado ao mesmo tempo ==
+
* <u>Sintaxe:</u>
  
−
* En PHP , a partires da versión 5, podemos recuperar o valor dun campo dun formulario e aplicarlle un filtro ao mesmo tempo.
+
::<syntaxhighlight lang="php" enclose="div">
−
: A función que permite facer isto é [http://php.net/manual/es/function.filter-input.php filter_input].
+
require '[path/]arquivo.php';
 +
</syntaxhighlight>
  
−
* Sintaxe:
+
* '''require''' fai o mesmo que '''include''', pero existe unha diferenza importante cando non se pode cargar o arquivo:
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
 
−
mixed filter_input ( int $type , string $variable_name [, int $filter = FILTER_DEFAULT [, mixed $options ]] )
 
−
</syntaxhighlight>
 
  
−
: Parámetros:
+
:* '''include''' produce un aviso de tipo '''E_WARNING''' e a execución do script pode continuar.
−
:* '''type''': INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER o INPUT_ENV.
+
:* '''require''' produce un erro de tipo '''Error'''. Se non se trata, a execución do script interrómpese.
−
:* '''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:
+
* Por este motivo empregaremos normalmente '''require''' cando o arquivo sexa imprescindible para que a aplicación poida funcionar.
  
−
:* En caso de éxito, valor da variable pedida, FALSE se o filtro faia ou NULL se a variable variable_name non está definida.
+
=== Exemplo con include ===
−
 
 
−
* Por exemplo:
 
−
::<syntaxhighlight lang="java" line enclose="div" highlight="" >
 
  
 +
::<syntaxhighlight lang="php" line enclose="div">
 +
<!DOCTYPE html>
 +
<html lang="gl">
 +
<head>
 +
    <meta charset="UTF-8">
 +
    <title>Exemplo con include</title>
 +
</head>
 +
<body>
 
<?php
 
<?php
−
$buscar_html = filter_input(INPUT_GET, 'buscar', FILTER_SANITIZE_SPECIAL_CHARS);
+
include __DIR__ . '/FuncionsExternasNonExiste.php';
−
$buscar_url = filter_input(INPUT_GET, 'buscar', FILTER_SANITIZE_ENCODED);
 
−
echo "Has buscado $buscar_html.\n";
 
−
echo "<a href='?buscar=$buscar_url'>Buscar de nuevo</a>";
 
−
?>
 
  
−
</syntaxhighlight>
+
echo 'Isto aparece porque include permite continuar a execución.';
−
 
 
−
* Información obtida de [http://php.net/manual/es/function.filter-input.php php.net].
 
−
 
 
−
 
 
−
== 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.
 
−
 
 
−
* Para facelo podemos usar a [http://php.net/manual/es/function.header.php función header] de PHP.
 
−
 
 
−
: 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 é:
 
−
 
 
−
::<syntaxhighlight lang="php" line enclose="div" highlight="" >
 
−
<?php
 
−
header('Location: http://www.nova_paxina.es/');
 
−
exit;
 
 
?>
 
?>
−
</syntaxhighlight>
+
</body>
−
 
+
</html>
−
:<u><b>Importante:</b></u>
+
</syntaxhighlight>
−
:* É NECESARIO QUE A CHAMADA Á FUNCIÓN header SE FAGA <u>ANTES</u> 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 <u>antes</u> da orde header.
 
−
:* Si existe código de script posteriormente á chamada do header será necesario poñer '''exit;''' despois da orde header para que non sigua a executar o script.
 
−
 
 
−
 
 
−
:: Tamén indicar que como veremos posteriormente cando enviamos datos con get, estes datos aparecen na páxina en forma de paráemtros &param1=valor1&param2=valor2&...polo tanto podemos facer unha redirección enviando datos na URL da forma:
 
−
::<syntaxhighlight lang="php" line enclose="div" highlight="" >
 
−
<?php
 
−
header('Location: http://www.nova_paxina.es?parametro1=valor1&paramentro2=valor2');
 
−
?>
 
−
</syntaxhighlight>
 
−
: E na seguinte páxina obter os datos con $_GET['parametro1'],...
 
−
 
 
−
 
 
−
 
 
−
 
 
−
 
 
−
 
 
−
<br />
 
−
* Un complemento interesante para visualizar a cabeceira dunha páxina: https://addons.mozilla.org/es/firefox/addon/live-http-headers/
 
−
: Ao instalalo teremos a posibilidade de capturar os datos de cabeceira da páxina se imos ao menú '''Herramientas''' => '''Live HTTP Headers'''.
 
−
 
 
−
<gallery caption="Complemento Live HTTP Headers" widths="350" heights="300px" perrow="2">
 
−
Image:Php_paso_datos_1.JPG| Unha vez instalado aparece unha nova opción de menú en Herramientas.
 
−
Image:Php_paso_datos_2.JPG| Coa ventá aberta, se cargamos unha páxina aparecen os datos enviados como cabeceira ao navegador web dende o servidor.
 
−
</gallery>
 
−
 
 
−
: Coa [http://php.net/manual/es/function.header.php 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 [http://wiki.cifprodolfoucha.es/index.php?title=PHP_Instalaci%C3%B3n_Apache 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 [http://wiki.cifprodolfoucha.es/index.php?title=DRUPAL_Instalaci%C3%B3n#Arquivos_de_configuraci.C3.B3n 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 [http://wiki.cifprodolfoucha.es/index.php?title=DRUPAL_Instalaci%C3%B3n#Arquivos_de_configuraci.C3.B3n 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
 
−
::<syntaxhighlight lang="php" line enclose="div" highlight="" >
 
−
cd /var/www/html
 
−
mkdir IMAXES
 
−
chown www-data:www-data IMAXES
 
−
chmod 755 IMAXES
 
−
</syntaxhighlight>
 
−
 
 
−
 
 
−
 
 
−
: 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
 
−
::<syntaxhighlight lang="php" line enclose="div" highlight="10,11" >
 
−
<IfModule unixd_module>
 
−
#
 
−
# If you wish httpd to run as a different user or group, you must run
 
−
# httpd as root initially and it will switch.
 
−
#
 
−
# User/Group: The name (or #number) of the user/group to run httpd as.
 
−
# It is usually good practice to create a dedicated user and group for
 
−
# running httpd, as with most system services.
 
−
#
 
−
User daemon
 
−
Group daemon
 
−
</IfModule>
 
−
</syntaxhighlight>  
 
−
 
 
−
:: 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'''
 
−
 
 
  
 +
: Se o arquivo non existe, aparecerá un warning, pero a execución poderá continuar.
  
 +
=== Exemplo con require ===
  
−
 
+
::<syntaxhighlight lang="php" line enclose="div">
−
'''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 [http://www.w3schools.com/php/php_file_upload.asp www3schools].
 
−
::<syntaxhighlight lang="php" line enclose="div" highlight="5,7" >
 
 
<!DOCTYPE html>
 
<!DOCTYPE html>
−
<html>
+
<html lang="gl">
 +
<head>
 +
    <meta charset="UTF-8">
 +
    <title>Exemplo con require</title>
 +
</head>
 
<body>
 
<body>
 +
<?php
 +
require __DIR__ . '/FuncionsExternasNonExiste.php';
  
−
<form action="GardaCampos.php" method="post" enctype="multipart/form-data">
+
echo 'Esta instrución non chegará a executarse se o erro non é tratado.';
−
    Selecciona unha imaxe para subir:
+
?>
−
    <input type="file" name="fileToUpload" id="fileToUpload">
 
−
    <input type="submit" value="Subir Imaxe" name="btnSubirImaxe">
 
−
</form>
 
−
 
 
 
</body>
 
</body>
 
</html>
 
</html>
−
</syntaxhighlight>  
+
</syntaxhighlight>
  
−
'''IMPORTANTE''':
+
: Neste caso, ao ser o arquivo obrigatorio, a execución interrómpese se non pode cargarse e o erro non é tratado.
−
:* 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.
+
<br />
 +
== require_once ==
  
 +
* <u>Sintaxe:</u>
  
−
'''Páxina que procesa os datos'''
+
::<syntaxhighlight lang="php" enclose="div">
−
:Pode ser a mesma do formulario ou outra diferente. No exemplo se chama 'GardaCampos.php'.
+
require_once '[path/]arquivo.php';
 +
</syntaxhighlight>
  
−
::<syntaxhighlight lang="php" line enclose="div" highlight="" >
+
* Ten o mesmo comportamento que '''require''', pero se o arquivo xa foi incluído previamente non se volverá incluír.
−
<?php
 
−
    // Enviamos datos
 
−
if(isset($_POST["btnSubirImaxe"])) {
 
−
    if(is_uploaded_file($_FILES["fileToUpload"]["tmp_name"])){  // Subido ao cartafol temporal do servidor
 
−
        $target_dir = $_SERVER['DOCUMENT_ROOT'] . "/IMAXES/";  // Gardaremos a imaxe no cartafol a onde apunta o servidor web máis /IMAXES => /var/www/html/IMAXES
 
−
        $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.  
 
  
−
        $tipo = $_FILES["fileToUpload"]["type"];
+
* É especialmente útil cando:
−
        if ($tipo=='image/jpeg')  {  // Neste exemplo verficamos que o arquivo sexa unha imaxe jpg
 
−
            if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
 
−
                echo "O arquivo ". basename( $_FILES["fileToUpload"]["name"]). " foi subido ao servidor.";
 
−
            } else {
 
−
                printf("Houbo un erro subindo o arquivo:%s",$_FILES['fileToUpload']['error']);
 
−
            }
 
−
        }
 
−
        else{
 
−
            echo ("O tipo de arquivo non é jpg");
 
−
        }
 
−
    }
 
−
    else{
 
−
        printf("Houbo un erro subindo o arquivo:%s",$_FILES['fileToUpload']['error']);
 
−
    }
 
  
 +
:* o arquivo é obrigatorio para o funcionamento da aplicación;
 +
:* non sabemos con certeza se xa foi cargado previamente;
 +
:* o arquivo define funcións, clases ou constantes que non deben declararse máis dunha vez.
  
−
}
+
: Resumo:
−
?>
 
−
</syntaxhighlight>
 
−
* En caso de erro, podemos ver o valor de $_FILES['fileToUpload']['error']:
 
−
:* UPLOAD_ERR_OK (0): Sen erros. O arquivo subiuse con éxito.
 
−
:* UPLOAD_ERR_INI_SIZE (1): O arquivo é máis grande que o tamaño máximo permitido especificado na configuración upload_max_filesize en php.ini.
 
−
:* UPLOAD_ERR_FORM_SIZE (2): O arquivo é máis grande que o tamaño máximo permitido especificado no formulario HTML mediante o atributo MAX_FILE_SIZE.
 
−
:* UPLOAD_ERR_PARTIAL (3): O arquivo subiuse parcialmente.
 
−
:* UPLOAD_ERR_NO_FILE (4): Non se subiu ningún arquivo. Isto pode ocorrer cando o campo de arquivo no formulario está baleiro ou se omite.
 
−
:* UPLOAD_ERR_NO_TMP_DIR (6): Falta o directorio temporal. Isto pode deberse a unha configuración incorrecta no servidor.
 
−
:* UPLOAD_ERR_CANT_WRITE (7): Non se puido escribir o arquivo no disco. Isto pode deberse a problemas de permisos no directorio de destino.
 
−
:* UPLOAD_ERR_EXTENSION (8): Unha extensión PHP detivo a subida do arquivo. Isto pode ocorrer cando unha extensión PHP específica bloquea a subida do arquivo.
 
  
 +
::{| class="wikitable"
 +
! Sentenza
 +
! O arquivo é obrigatorio
 +
! Evita incluílo máis dunha vez
 +
|-
 +
| include
 +
| Non
 +
| Non
 +
|-
 +
| include_once
 +
| Non
 +
| Si
 +
|-
 +
| require
 +
| Si
 +
| Non
 +
|-
 +
| require_once
 +
| Si
 +
| Si
 +
|}
  
−
: <u>'''Nota importante:'''</u> Algunhas veces ['error'] sempre devolve false (0) e non se establece correctamente o error.
+
<br />
−
: Para saber que pasa, temporalmente podemos poñer ao principio da páxina:
+
== Configuración da visualización e rexistro de erros ==
−
::<syntaxhighlight lang="php" line enclose="div" highlight="" >
 
−
    error_reporting(E_ALL);
 
−
    ini_set('display_errors', 1);
 
−
</syntaxhighlight>
 
  
 +
* Durante o desenvolvemento é importante detectar e corrixir erros, warnings e mensaxes de depreciación.
  
 +
* Nun servidor de produción, pola contra, non debemos amosar directamente os erros ao usuario, xa que poden revelar información interna da aplicación ou do servidor.
  
−
* ALgunhas función que pode ser de utilidade:
+
=== Entorno de desenvolvemento ===
−
:* [http://php.net/manual/es/function.basename.php función basename] devolve a última parte dunha ruta. Así se teño c:\carpeta1\carpeta2\arquivo.jpg devolverá 'arquivo.jpg'.
 
−
:: Por exemplo:
 
−
:::$target_dir = $_SERVER['DOCUMENT_ROOT'] . "/IMAXES/";  // Gardaremos a imaxe no cartafol a onde apunta o servidor web máis /IMAXES => /var/www/html/IMAXES
 
−
:::$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.
 
  
 +
* Durante o desenvolvemento podemos pedir a PHP que informe de todos os erros:
  
−
:* A [http://php.net/manual/es/function.pathinfo.php función pathinfo] garda a extensión do arquivo a subir.
+
::<syntaxhighlight lang="php" enclose="div">
−
:: Por exemplo:
+
error_reporting(E_ALL);
−
:::$imageFileType = pathinfo($target_file,PATHINFO_EXTENSION);
+
ini_set('display_errors', '1');
 +
</syntaxhighlight>
  
−
:* A [http://php.net/manual/es/function.getimagesize.php función getimagesize] devolve un array con información da imaxe. En caso de que non sexa unha imaxe devolve false.
+
* '''E_ALL''' indica que queremos recibir todos os erros, warnings, notices e mensaxes de depreciación configuradas por PHP.
−
:::Por exemplo:
 
−
:::$check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
 
−
:::if($check !== false) {
 
−
:::    echo "O arquivo é unha imaxe - " . $check["mime"] . ".";
 
−
:::    } else {
 
−
:::        echo "O arquivo non é unha imaxe.";
 
−
:::    }
 
  
 +
=== Entorno de produción ===
  
 +
* Nun entorno de produción é recomendable non amosar os erros ao usuario e gardalos no rexistro do servidor.
  
−
* Debemos ter en conta que podemos subir outro tipo de arquivos, como documentos,...iso dependerá da nosa aplicación.
+
: Unha configuración típica no arquivo ''php.ini'' sería:
−
: Podemos mellorar o noso código introducindo novas condicións.
 
  
 +
::<syntaxhighlight lang="ini" enclose="div">
 +
display_errors = Off
 +
log_errors = On
 +
error_reporting = E_ALL
 +
</syntaxhighlight>
  
 +
* Desta forma os erros seguirán rexistrándose, pero non se amosarán directamente na páxina web.
  
−
* '''Verificar se o arquivo existe antes de subilo''':
+
=== Máscaras de erros ===
−
::<syntaxhighlight lang="php" line enclose="div" highlight="" >
 
−
<?php
 
−
if (file_exists($target_file)) {
 
−
    echo "Ese arquivo xa existe.";
 
−
    $uploadOk = 0;
 
−
}
 
−
?>
 
−
</syntaxhighlight>
 
  
 +
* PHP tamén permite combinar constantes de erros mediante operadores a nivel de bits.
  
 +
: Por exemplo:
  
−
* '''Limitar o tipo do arquivo''':
+
::<syntaxhighlight lang="php" enclose="div">
−
::<syntaxhighlight lang="php" line enclose="div" highlight="" >
+
// Erros, warnings e erros de análise.
−
<?php
+
error_reporting(E_ERROR | E_WARNING | E_PARSE);
−
$imageFileType = $_FILES["fileToUpload"]["type"];
 
−
if($imageFileType != "image/jpeg" && $imageFileType != "/image/png" && $imageFileType != "image/jpg"
 
−
&& $imageFileType != "image/gif" ) {
 
−
    echo "Soamente arquivos JPG, JPEG, PNG & GIF están permitidos.";
 
−
    $uploadOk = 0;
 
−
}
 
−
?>
 
−
</syntaxhighlight>
 
  
 +
// Todos os erros excepto E_NOTICE.
 +
error_reporting(E_ALL & ~E_NOTICE);
 +
</syntaxhighlight>
  
 +
: Aínda que esta posibilidade existe, durante o desenvolvemento empregaremos normalmente:
  
−
* '''Limitar o tamaño do arquivo''':
+
::<syntaxhighlight lang="php" enclose="div">
−
::<syntaxhighlight lang="php" line enclose="div" highlight="" >
+
error_reporting(E_ALL);
−
<?php
+
</syntaxhighlight>
−
// Check file size
 
−
if ($_FILES["fileToUpload"]["size"] > 500000) {
 
−
    echo "O arquivo ten máis de 500KB. Non se pode subir";
 
−
    $uploadOk = 0;
 
−
}
 
−
?>
 
−
</syntaxhighlight>  
 
  
−
:* Para o tamaño do arquivo podemos empregar outra aproximación, que consiste en poñer un campo oculto <u>antes do campo de tipo file</u> da seguinte forma:
+
=== A través do arquivo .htaccess ===
−
::<syntaxhighlight lang="php" line enclose="div" highlight="3" >
 
−
<form action="GardaCampos.php" method="post" enctype="multipart/form-data">
 
−
    Selecciona unha imaxe para subir:
 
−
    <input type="hidden" name="MAX_FILE_SIZE" value="10000" /> 
 
−
    <input type="file" name="fileToUpload" id="fileToUpload">
 
−
    <input type="submit" value="Subir Imaxe" name="btnSubirImaxe">
 
−
</form>
 
−
</syntaxhighlight>
 
−
: O nome ten que ser MAX_FILE_SIZE e o value é o tamaño máximo en bytes.
 
  
−
:: Cando se procesa o formulario:
+
* Se PHP se executa como módulo de Apache e a configuración do servidor o permite, é posible modificar determinadas opcións de PHP mediante o arquivo '''.htaccess'''.
−
::<syntaxhighlight lang="php" line enclose="div" highlight="5,6" >
 
−
<?php
 
−
if(isset($_POST["btnSubirImaxe"])) {
 
−
    $target_dir = $_SERVER['DOCUMENT_ROOT'] . "/IMAXES/";  // Gardaremos a imaxe no cartafol a onde apunta o servidor web máis /IMAXES => /var/www/html/IMAXES
 
−
    $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.
 
−
    if ($_FILES['fileToUpload']['error']>0)
 
−
        die("Houbo un erro subindo o arquivo: " . $_FILES['fileToUpload']['error']);  // Neste exemplo dará de erro o valor 2 => UPLOAD_ERR_FORM_SIZE (visto anteriormente)
 
  
−
    ......
+
: Por exemplo:
−
 
 
−
?>
 
−
</syntaxhighlight>
 
−
 
 
−
 
 
−
 
 
−
: 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 [http://angelfernandezgonzalez.blogspot.com.es/2015/10/subir-archivos-de-mas-de-8mb-en.html 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.
 
  
 +
::<syntaxhighlight lang="apache" enclose="div">
 +
php_value error_reporting 2147483647
 +
php_flag display_errors On
 +
</syntaxhighlight>
  
−
:: 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í).
+
* Esta forma de configuración '''non é válida para todas as formas de executar PHP'''.
−
::* Opción a)
 
−
:::: Crear un arquivo '''php.ini''' no cartafol raíz do noso sitio web e poñer:
 
−
:::::<syntaxhighlight lang="php" line enclose="div" highlight="" >
 
−
upload_max_filesize = 64M
 
−
post_max_size = 64M
 
−
max_execution_time = 300
 
−
</syntaxhighlight>
 
−
::::: 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:
 
−
:::::<syntaxhighlight lang="php" line enclose="div" highlight="" >
 
−
php_value upload_max_filesize 64M
 
−
php_value post_max_size 64M
 
−
php_value max_execution_time 300
 
−
php_value max_input_time 300
 
−
</syntaxhighlight>
 
−
::::: No exemplo estamos a limitar en 64MB o tamaño da subida e o tempo de execución en 5 minutos.
 
  
 +
: Por exemplo, cando PHP se executa mediante CGI/FastCGI poden empregarse arquivos '''.user.ini''' para determinadas opcións de configuración.
  
 
<br />
 
<br />
 +
== Colocar arquivos sensibles ==
  
−
== Verificando os datos dun formulario ==
+
* Veremos nas seguintes unidades que teremos que gardar información sensible en certos arquivos PHP, como os datos necesarios para conectarnos a unha base de datos.
  
−
* Unha forma rápida de verificar que certos datos dun formulario teñan información sería:
+
* Podemos definir esa información nun arquivo PHP, por exemplo ''informacionbd.php'', e incorporalo mediante '''require''' ou '''require_once''' nas páxinas que necesiten utilizalo.
−
::<syntaxhighlight lang="php" line enclose="div" highlight="" >
 
−
<?php
 
−
// Campos obrigatorios
 
−
$campos_obrigatorios = array('txtNome', 'txtEmail');
 
  
−
// Comprobamos que os campos obrigatorios teñan datos
+
* Para evitar que este tipo de arquivos poidan solicitarse directamente desde o navegador, é recomendable situalos fisicamente fóra do '''DocumentRoot''' do servidor web.
−
$erro = false;
 
−
foreach ($campos_obrigatorios as $campo) {
 
−
  if (empty($_POST[$campo])) $erro = true;
 
−
}
 
  
−
if ($erro) {
+
: Por exemplo, se Apache publica:
−
  // Non existe algún dos campos obrigatorios
 
−
}
 
  
 +
::<syntaxhighlight lang="text">
 +
/var/www/html
 
</syntaxhighlight>
 
</syntaxhighlight>
  
−
== Creando arrays cos datos dun formulario ==
+
: podemos gardar o arquivo de configuración en:
−
 
 
−
* Algunhas veces, cando xeramos formularios dinamicamente, teremos que asignar un nome a cada campo do formulario. Pero neste tipo de formularios dinámicos non sabemos cantos 'nomes' imos xerar.
 
−
 
 
−
* Imaxinemos unha páxina na que queremos xerar dinamicamente un formulario de alta de novos exemplares dun libro determinado.
 
−
: Así temos un libros cos seus datos (titulo, isbn,...)
 
−
: Dispoñemos de exemplares no que queremos gardar: estado (bo, mal, normal).
 
−
 
 
−
: Cando eu dea de alta o libro vou dar os seus datos máis o número de exemplares. Imaxinemos que poño que do libro 'A illa do tesouro' teño 3 exemplares.
 
−
: Este dato pode variar dun libro a outro e non sei de antemán cantos exemplares vou ter.
 
  
−
: Se creo agora o formulario para eses 3 exemplares tería que crear algo así:
+
::<syntaxhighlight lang="text">
−
::<syntaxhighlight lang="php" line enclose="div" highlight="" >
+
/var/www/configuracions/informacionbd.php
−
<input type='text' name='txtEstado1' />
 
−
<input type='text' name='txtEstado2' />
 
−
<input type='text' name='txtEstado3' />
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
−
Cando eu preme o 'action' do formulario os datos pasará á seguinte páxina e eu tería que saber cantos 'txtEstado?' se envían.
+
* Ademais, debemos:
−
 
 
−
* Unha forma moito máis sinxela de facelo é a seguinte:
 
−
 
 
−
* Definimos o campo que vai levar o estado có seguinte nome: txtEstado'''[ ]'''
 
−
: Creamos cada input desta forma:
 
−
::<syntaxhighlight lang="php" line enclose="div" highlight="" >
 
−
for($cont=0;$cont<$numExemplares;$cont++){
 
−
<input type='text' name='txtEstado[]' />
 
−
}
 
−
</syntaxhighlight>
 
−
 
 
−
* Cando estes datos cheguen á seguinte páxina o dato: $_POST['txtEstado'] vai ser un array cos datos de todos os exemplares e xa podemos traballar con el como ata o de agora.
 
−
 
 
−
 
 
  
 +
:* configurar correctamente os permisos do arquivo;
 +
:* evitar gardar contrasinais ou credenciais en repositorios públicos;
 +
:* permitir o acceso unicamente ao usuario ou servizo que realmente o necesite.
  
 
<br />
 
<br />
 
== Exercicios propostos ==
 
== Exercicios propostos ==
  
−
* '''Exercicio 1:''' Crea unha páxina cun formulario e dous campos, nome e idade. O método de envío debe ser aquel que o os datos van dentro do corpo do formulario. O destino do formulario é a mesma páxina (non vale empregar o URL escrita a man). O campo de nome non debe deixar escribir máis de vinte caracteres e o de idade dous caracteres. Terá un botón Enviar Datos. En caso de que se envíen os datos, amosará nunha lista os datos enviados. No caso de que non se envíe algún dato debe amosar un texto indicando que o dato é obrigatorio e amosar outra vez o formulario. Deberás verificar que o que se envía e un número (idade) de dous caracteres e un nome (cadea) quitando todos os caracteres que poidan dar lugar a algún tipo de ataque de inxección de código. Deberá amosar en forma de lista os datos enviados e non amosar o formulario.
+
* '''Exercicio 1:''' Define nun arquivo externo dentro dun cartafol de nome ''utilidades'' dúas funcións:
−
 
 
−
 
 
−
 
 
−
* '''Exercicio 2:''' Fai o necesario para xestionar as operacións de alta, baixa e modifcación dunha lista de froitas. Se debe asegurar que no texto da froita non se poida empregar nun ataque XSS ou de inxección de código. Se ven baleiro o campo de texto debe amosar o erro. Debe amosarse en forma de táboa a lista de froitas engadidas. Ao carón de cada froita debe aparecer un botón cun texto eliminar, que borre dito elemento da lista de froitas. Se non hai elementos na lista debe amosar o texto 'Cesta baleira'. Nun arquivo separado de nome operacionsFroitas, se gardará nunha variable o array de froitas e as funcións para verificar que o nome da froita sexa correcto e cambiar no nome os caracteres non permitidos. Se ven baleiro debe devolver false. Outra función para engadir unha froita ao array e se a froita xa estivera engadidad non facer nada, una función que dada unha froita, a elimine do array se existe. Dito arquivo é necesario para o funcionamento da páxina principal e sabemos que non vai cargarse nada máis que unha vez. Terá de nome operaciónsFroitas.php e estará gardado no cartafol /utilidades/.
 
−
 
 
−
 
 
−
 
 
−
* '''Exercicio 3:''' Crea nun arquivo separado de nome /utilidades/usuarios, un array de datos de usuario (cada usuario ten: id, nome, tfno, email). Nese mesmo arquivo define unha función de nome obterUsuarioPorID que en base a un id, busque no array de usuarios, toda a información do usuario con ese id e que devolva toda a información dese usuario se existe. Se non existe debe devolver null. Amosa unha páxina de nome listaUsuarios, unha lista de nomes de usuario, en forma de enlace. Ao premer no nome, deberá amosar toda a información do usuario noutra páxina diferente de nome detalleUsuario . Esa segunda páxina terá un enlace para ir á primeira páxina e volver a listar os usuarios.
 
−
: Se envías un id que non existe deberá amosar unha mensaxe. Comproba como podes modificar na URL o número de ID a buscar.
 
−
 
 
−
 
 
−
 
 
−
 
 
−
 
 
−
 
 
−
 
 
  
 +
:* unha función que, a partir dunha cadea, engada dita cadea a un array se non existe previamente;
 +
:* outra función que, dado un array, devolva unha copia do array recibido.
  
 +
: Xera unha páxina que faga uso das funcións do arquivo anterior. O arquivo é obrigatorio para o funcionamento da páxina.
  
  
 +
* '''Exercicio 2:''' Define nun arquivo externo de nome ''utilidades2.php'', dentro do cartafol ''utilidades'', as seguintes constantes:
  
 +
:* '''NUM_ELEMENTOS''' igual a 3;
 +
:* '''IDADE_MAIOR''' igual a 18.
  
 +
: Crea tamén unha función que, dado un array numérico, comprobe que o número de elementos do array sexa superior a '''NUM_ELEMENTOS'''.
  
 +
: Se non se cumpre esta condición, a función debe devolver '''false'''.
  
 +
: En caso contrario, debe devolver un array cos elementos que sexan maiores que '''IDADE_MAIOR'''. Se ningún elemento cumpre a condición, debe devolver '''false'''.
  
 +
: Crea unha páxina de exemplo de uso da función anterior, tendo en conta que a páxina pode xerarse dinamicamente e non sabemos se o arquivo foi incluído previamente. A páxina necesita cargar obrigatoriamente o arquivo ''utilidades2.php''.
  
 
<br />
 
<br />
 
=== Solución Exercicios propostos ===
 
=== Solución Exercicios propostos ===
  
−
* '''Solución Exercicio 1:''' Crea unha páxina cun formulario e dous campos, nome e idade. O método de envío debe ser aquel que o os datos van dentro do corpo do formulario. O destino do formulario é a mesma páxina (non vale empregar o URL escrita a man). O campo de nome non debe deixar escribir máis de vinte caracteres e o de idade dous caracteres. Terá un botón Enviar Datos. En caso de que se envíen os datos, amosará nunha lista os datos enviados. No caso de que non se envíe algún dato debe amosar un texto indicando que o dato é obrigatorio e amosar outra vez o formulario. Deberás verificar que o que se envía e un número (idade) de dous caracteres e un nome (cadea) quitando todos os caracteres que poidan dar lugar a algún tipo de ataque de inxección de código. Deberá amosar en forma de lista os datos enviados e non amosar o formulario.
+
* '''Solución Exercicio 1'''
−
 
 
−
::<syntaxhighlight lang="php" enclose="div" highlight="" >
 
−
<!DOCTYPE html>
 
−
<html lang="gl">
 
−
<head>
 
−
    <meta charset="UTF-8">
 
−
    <title>Formulario en Galego</title>
 
−
</head>
 
−
<body>
 
−
<?php
 
−
$nome = "";
 
−
$idade = "";
 
−
$erros = array();
 
−
$formulario_mostrado = true; // Variable para controlar si se muestra el formulario
 
−
 
 
−
 
 
−
if (isset($_POST['btnEnviar'])) {  // Vimos de premer o botón btnEnviar
 
−
    // Recoller e limpar os datos enviados
 
−
    $nome = filter_input(INPUT_POST, 'nome', FILTER_SANITIZE_STRING); // Deprecated. Mellor => filter_input(INPUT_POST, 'nome', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_NO_ENCODE_QUOTES);
 
−
    $idade = filter_input(INPUT_POST, 'idade', FILTER_SANITIZE_STRING);  // Deprecated. Mellor => filter_input(INPUT_POST, 'idade', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_NO_ENCODE_QUOTES);
 
−
 
 
−
 
 
−
    // Validación dos datos
 
−
    if (empty($nome)) {
 
−
        $erros[] = "O campo nome é obrigatorio.";
 
−
    } elseif (strlen($nome) > 20) {
 
−
        $erros[] = "O campo nome non pode ter máis de 20 caracteres.";
 
−
    }
 
−
 
 
−
    if (empty($idade)) {
 
−
        $erros[] = "O campo idade é obrigatorio.";
 
−
    } elseif (!(filter_input(INPUT_POST, 'idade', FILTER_VALIDATE_INT) && $idade > 0)) {
 
−
        $erros[] = "A idade debe ser un número positivo.";
 
−
    } elseif (strlen($idade) != 2) {
 
−
        $erros[] = "A idade debe ter exactamente dous caracteres.";
 
−
    }
 
−
}
 
−
else{  // Pode vir de premer no enlace cando amosa os datos
 
−
    $erros[] = "Non enviaches datos.";
 
−
}
 
−
// Comprobar si hay errores
 
−
if (empty($erros)) {
 
−
  $formulario_mostrado = false; // No mostrar el formulario si no hay errores
 
−
}
 
−
?>
 
−
 
 
−
<?php
 
−
if ($formulario_mostrado) {
 
−
    // Mostrar el formulario
 
−
    ?>
 
−
    <h2>Formulario</h2>
 
−
    <form method="POST" action="<?php echo htmlentities($_SERVER["PHP_SELF"]); ?>">
 
−
        <label for="nome">Nome:</label>
 
−
        <input type="text" id="nome" name="nome" maxlength="20" value="<?php echo $nome; ?>"><br><br>
 
−
 
 
−
        <label for="idade">Idade:</label>
 
−
        <input type="text" id="idade" name="idade" maxlength="2" size="3" value="<?php echo $idade; ?>"><br><br>
 
−
 
 
−
        <input type="submit" name="btnEnviar" value="Enviar Datos"><br><br>
 
−
    </form>
 
−
 
 
−
<?php
 
−
}
 
−
if(empty($erros)) {
 
−
    // Mostrar os datos enviados nunha lista
 
−
    echo "<h2>Datos enviados:</h2>";
 
−
    echo "<ul>";
 
−
    echo "<li>Nome: $nome</li>";
 
−
    echo "<li>Idade: $idade</li>";
 
−
    echo "</ul>";
 
−
}
 
−
else {
 
−
    // Mostrar erros
 
−
    echo "<h2>Erros:</h2>";
 
−
    echo "<ul>";
 
−
    foreach ($erros as $erro) {
 
−
        echo "<li>$erro</li>";
 
−
    }
 
−
    echo "</ul>";
 
−
}
 
−
?>
 
−
 
 
−
</body>
 
−
</html>
 
−
</syntaxhighlight>
 
−
 
 
−
 
 
  
−
<br />
+
: '''Páxina utilidades/utilidades1.php'''
−
* '''Solución Exercicio 2:''' Fai o necesario para xestionar as operacións de alta, baixa e modifcación dunha lista de froitas. Se debe asegurar que no texto da froita non se poida empregar nun ataque XSS ou de inxección de código. Se ven baleiro o campo de texto debe amosar o erro. Debe amosarse en forma de táboa a lista de froitas engadidas. Ao carón de cada froita debe aparecer un botón cun texto eliminar, que borre dito elemento da lista de froitas. Se non hai elementos na lista debe amosar o texto 'Cesta baleira'. Nun arquivo separado de nome operacionsFroitas, se gardará nunha variable o array de froitas e as funcións para verificar que o nome da froita sexa correcto e cambiar no nome os caracteres non permitidos. Se ven baleiro debe devolver false. Outra función para engadir unha froita ao array e se a froita xa estivera engadidad non facer nada, una función que dada unha froita, a elimine do array se existe. Dito arquivo é necesario para o funcionamento da páxina principal e sabemos que non vai cargarse nada máis que unha vez. Terá de nome operaciónsFroitas.php e estará gardado no cartafol /utilidades/.
 
  
−
: '''Arquivo /utilidades/operacionsFroitas.inc.php'''
+
::<syntaxhighlight lang="php" enclose="div">
−
::<syntaxhighlight lang="php" enclose="div" highlight="" >
 
 
<?php
 
<?php
−
// Array para gardar as froitas
 
−
$listaFroitas = [];
 
−
 
−
/**
 
−
* Verifica se o nome dunha froita é válido.
 
−
*
 
−
* Esta función limpa o nome da froita de caracteres non permitidos. 
 
−
* - Se o nome está baleiro despois da limpeza, devolve `false`. 
 
−
* - Se é válido, devolve o nome da froita limpo.
 
−
*
 
−
* @param string $nome Nome da froita a verificar.
 
−
*
 
−
* @return string|false Nome da froita limpo ou `false` se está baleiro.
 
−
*/
 
−
function verificarNomeFroita(string $nome): string|false {
 
−
    // Deprecado: filter_var($nome, FILTER_SANITIZE_STRING);
 
−
    // Mellor uso recomendado: filter_var con FILTER_SANITIZE_FULL_SPECIAL_CHARS
 
−
    $nome = filter_var($nome, FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_NO_ENCODE_QUOTES);
 
−
 
−
    if (empty($nome)) {
 
−
        return false;
 
−
    } else {
 
−
        return $nome;
 
−
    }
 
−
}
 
  
 
/**
 
/**
−
  * Engade unha froita á lista global se non existe xa.
+
  * Engade unha cadea ao array se non existe xa.
 
  *
 
  *
−
  * @param string $nomeFroita Nome da froita a engadir.
+
* @param array  &$array Array onde se engadirá a cadea.
 +
  * @param string $cadea  Cadea de texto a engadir.
 
  *
 
  *
 
  * @return void
 
  * @return void
 
  */
 
  */
−
function engadirFroita(string $nomeFroita): void {
+
function engadirCadeaAoArray(array &$array, string $cadea): void
−
    global $listaFroitas;
+
{
−
   
+
     if (!in_array($cadea, $array, true)) {
−
     if (!in_array($nomeFroita, $listaFroitas)) {
+
         $array[] = $cadea;
−
         $listaFroitas[] = $nomeFroita;
 
 
     }
 
     }
 
}
 
}
  
 
/**
 
/**
−
  * Elimina unha froita da lista global.
+
  * Devolve unha copia dun array.
 
  *
 
  *
−
  * @param string $nomeFroita Nome da froita a eliminar.
+
  * En PHP os arrays asígnanse por valor. Polo tanto, devolver o array
 +
* permite obter unha copia que pode modificarse sen alterar o array orixinal.
 
  *
 
  *
−
  * @return void
+
  * @param array $array Array que se quere copiar.
−
*/
 
−
function eliminarFroita(string $nomeFroita): void {
 
−
    global $listaFroitas;
 
−
    $indice = array_search($nomeFroita, $listaFroitas);
 
−
    if ($indice !== false) {
 
−
        unset($listaFroitas[$indice]);
 
−
    }
 
−
}
 
−
 
 
−
/**
 
−
* Obtén a lista de froitas.
 
 
  *
 
  *
−
  * @return array Array coas froitas actuais na lista global.
+
  * @return array Copia do array recibido.
 
  */
 
  */
−
function obterListaFroitas(): array {
+
function copiarArray(array $array): array
−
    global $listaFroitas;
+
{
−
     return $listaFroitas;
+
     return $array;
 
}
 
}
−
 
−
 
−
?>
 
−
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
: '''Páxina exercicio1_include.php'''
  
−
: '''Arquivo xestionFroitas.php'''
+
::<syntaxhighlight lang="php" enclose="div">
−
::<syntaxhighlight lang="php" enclose="div" highlight="" >
 
 
<!DOCTYPE html>
 
<!DOCTYPE html>
−
<html>
+
<html lang="gl">
 
<head>
 
<head>
−
     <title>Xestión de Lista de Froitas</title>
+
    <meta charset="UTF-8">
 +
     <title>Exemplo PHP en Galego</title>
 
</head>
 
</head>
 
<body>
 
<body>
−
    <h1>Xestión de Lista de Froitas</h1>
+
<?php
−
 
+
require __DIR__ . '/utilidades/utilidades1.php';
−
    <?php
 
−
    // Incluímos o arquivo operacionsFroitas.inc.php
 
−
    require 'utilidades/operacionsFroitas.inc.php';
 
  
−
    // Xa tiñamos froitas no listado en forma de campos ocultos
+
$meuArray = [];
−
    if (isset($_POST['listaFroitas'])) $listaFroitas = $_POST['listaFroitas'];
 
−
    if (isset($_POST['btnBaleirar'])) $listaFroitas = array();
 
  
−
    // Comprobamos se se enviou unha nova froita => pulsa botón
+
// Engadir cadeas ao array.
−
    if (isset($_POST['btnEngadir']) && isset($_POST['novaFroita'])) {  // Non verifico empty xa que o fai a función
+
engadirCadeaAoArray($meuArray, 'Ola');
−
        $novaFroita = verificarNomeFroita($_POST['novaFroita']);
+
engadirCadeaAoArray($meuArray, 'Mundo');
−
        // Verificamos se o nome da froita é válido
+
engadirCadeaAoArray($meuArray, 'Ola'); // Xa existe e non se engadirá de novo.
−
        if ($novaFroita) {
 
−
            engadirFroita($novaFroita);
 
−
        } else {
 
−
            echo "<p class='erro'>Non introducido o nome da froita.</p>";
 
−
        }
 
−
    }
 
  
−
    // Comprobamos se se enviou unha froita para eliminar
+
// Copiar o array.
−
    if (isset($_POST['btnBorrar'])) {
+
$copiaArray = copiarArray($meuArray);
−
        $froitaAEliminar = $_POST['btnBorrar'];
 
−
        eliminarFroita($froitaAEliminar);
 
−
    }
 
  
−
    // Obtemos a lista de froitas
+
echo '<h2>Array orixinal:</h2>';
−
    $listaFroitas = obterListaFroitas();
+
echo '<pre>';
 +
print_r($meuArray);
 +
echo '</pre>';
  
−
    // Amosamos a táboa de froitas ou a mensaxe de cesta baleira
+
echo '<h2>Copia do array:</h2>';
−
    if (empty($listaFroitas)) {
+
echo '<pre>';
−
        echo "<p>Cesta baleira.</p>";
+
print_r($copiaArray);
−
    }
+
echo '</pre>';
−
    echo "<h2>Operacións Froita</h2>";
+
?>
−
    printf('<form method="post" action="%s">',htmlentities($_SERVER['PHP_SELF']));
 
−
        echo "<table>";
 
−
        echo "<tr><th>Froita</th><th>Acción</th></tr>";
 
−
        foreach ($listaFroitas as $key=>$froita) {
 
−
            echo "<tr>";
 
−
            echo "<td>$froita";
 
−
            printf('<input type="hidden" value="%s" name="listaFroitas[%s]" />',$froita,$key);
 
−
            echo "</td>";
 
−
            printf("<td><button type='submit' id='btnBorrar' name='btnBorrar' value='%s'>Borrar</button></td>",$froita);
 
−
            echo "</tr>";
 
−
        }
 
−
        echo "</table>";
 
−
    ?>
 
−
 
 
−
        <label for="novaFroita">Nome da Froita:</label>
 
−
        <input type="text" id="novaFroita" name="novaFroita">
 
−
        <button type="submit" name='btnEngadir' value='engadir'>Engadir Froita</button>
 
−
        <?php if(!empty($listaFroitas)) ?>
 
−
            <div><button type="submit" name='btnBaleirar' value='baleirar'>Baleirar Cesta</button></div>
 
−
           
 
−
 
 
−
    </form>
 
 
</body>
 
</body>
 
</html>
 
</html>
−
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
<br />
 +
* '''Solución Exercicio 2'''
  
 +
: '''Páxina utilidades/utilidades2.php'''
  
−
<br />
+
::<syntaxhighlight lang="php" enclose="div">
−
* '''Solución Exercicio 3:''' Crea nun arquivo separado de nome /utilidades/usuarios, un array de datos de usuario (cada usuario ten: id, nome, tfno, email). Nese mesmo arquivo define unha función de nome obterUsuarioPorID que en base a un id, busque no array de usuarios, toda a información do usuario con ese id e que devolva toda a información dese usuario se existe. Se non existe debe devolver null. Amosa unha páxina de nome listaUsuarios, unha lista de nomes de usuario, en forma de enlace. Ao premer no nome, deberá amosar toda a información do usuario noutra páxina diferente de nome detalleUsuario . Esa segunda páxina terá un enlace para ir á primeira páxina e volver a listar os usuarios.
+
<?php
−
: Se envías un id que non existe deberá amosar unha mensaxe. Comproba como podes modificar na URL o número de ID a buscar.
 
  
−
: '''Páxina usuarios.inc.php'''
+
const NUM_ELEMENTOS = 3;
−
::<syntaxhighlight lang="php" enclose="div" highlight="" >
+
const IDADE_MAIOR = 18;
−
<?php
 
−
// Array de datos de usuarios (id, nome, tfno, email)
 
−
$usuarios = [
 
−
    ["id" => 1, "nome" => "Usuario 1", "tfno" => "123456789", "email" => "usuario1@example.com"],
 
−
    ["id" => 2, "nome" => "Usuario 2", "tfno" => "987654321", "email" => "usuario2@example.com"],
 
−
    ["id" => 3, "nome" => "Usuario 3", "tfno" => "555555555", "email" => "usuario3@example.com"]
 
−
];
 
  
 
/**
 
/**
−
  * Obtén os datos dun usuario a partir do seu ID.
+
  * Comproba as idades dun array e devolve os elementos que superen un límite.
−
*
 
−
* Esta función percorre a lista global de usuarios e devolve o usuario cuxo ID coincida co proporcionado. 
 
−
* - Se non se atopa ningún usuario con ese ID, devolve `null`.
 
 
  *
 
  *
−
  * @param int $id ID do usuario que se quere buscar.
+
  * @param array $array Array de números (idades) a comprobar.
 
  *
 
  *
−
  * @return array|null Array asociativo coas datos do usuario se se atopa, ou `null` se non existe.
+
  * @return array|false Devolve un array cos elementos maiores que IDADE_MAIOR
 +
*                    ou false se non se cumpren as condicións.
 
  */
 
  */
−
function obterUsuarioPorID(int $id): array|null {
+
function comprobarIdade(array $array): array|false
−
     global $usuarios;
+
{
−
   
+
     $elementosCumpridos = [];
−
     foreach ($usuarios as $usuario) {
+
 
−
        if ($usuario["id"] == $id) {
+
     if (count($array) <= NUM_ELEMENTOS) {
−
            return $usuario;
+
        return false;
−
        }
 
 
     }
 
     }
−
   
 
−
    return null; // Devolve null se o usuario non se atopa
 
−
}
 
−
?>
 
−
</syntaxhighlight>
 
  
−
: '''Páxina listaUsuarios.php'''
+
     foreach ($array as $idade) {
−
::<syntaxhighlight lang="php" enclose="div" highlight="" >
+
         if ($idade > IDADE_MAIOR) {
−
<!DOCTYPE html>
+
            $elementosCumpridos[] = $idade;
−
<html>
+
        }
−
<head>
 
−
    <title>Listado de Usuarios</title>
 
−
</head>
 
−
<body>
 
−
    <h1>Listado de Usuarios</h1>
 
−
 
 
−
    <?php
 
−
    require_once 'utilidades/usuarios.inc.php';
 
−
 
 
−
    // Amosar a lista de usuarios como enlaces
 
−
    echo "<ul>";
 
−
     foreach ($usuarios as $usuario) {
 
−
         echo "<li><a href='detalleUsuario.php?id={$usuario["id"]}'>{$usuario["nome"]}</a></li>";
 
 
     }
 
     }
−
    echo "</ul>";
 
−
    ?>
 
−
</body>
 
−
</html>
 
  
 +
    return $elementosCumpridos !== [] ? $elementosCumpridos : false;
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
: '''Páxina exercicio2_include.php'''
  
−
; '''Páxina detalleUsuario.php'''
+
::<syntaxhighlight lang="php" enclose="div">
−
::<syntaxhighlight lang="php" enclose="div" highlight="" >
 
 
<!DOCTYPE html>
 
<!DOCTYPE html>
−
<html>
+
<html lang="gl">
 
<head>
 
<head>
−
     <title>Detalles do Usuario</title>
+
    <meta charset="UTF-8">
 +
     <title>Exemplo PHP en Galego</title>
 
</head>
 
</head>
 
<body>
 
<body>
−
    <h1>Detalles do Usuario</h1>
+
<?php
 +
require_once __DIR__ . '/utilidades/utilidades2.php';
  
−
    <?php
+
$idades = [2, 62, 2, 2, 2]; // Soamente 62 cumpre a condición.
−
    require 'utilidades/usuarios.inc.php';
 
  
−
    // Verificar se se pasou un ID válido por parámetro
+
$resultado = comprobarIdade($idades);
−
    if (isset($_GET["id"])) {
 
−
        $idUsuario = htmlentities($_GET["id"]);
 
−
        // Chamar á función para obter os datos do usuario
 
−
        $usuarioSeleccionado = obterUsuarioPorID($idUsuario);
 
  
−
        // Amosar os detalles do usuario
+
if ($resultado !== false) {
−
        if ($usuarioSeleccionado !== null) {
+
    echo '<h2>Idades que cumpren a condición:</h2>';
−
            echo "<p>Nome: {$usuarioSeleccionado["nome"]}</p>";
+
    echo '<ul>';
−
            echo "<p>Teléfono: {$usuarioSeleccionado["tfno"]}</p>";
+
 
−
            echo "<p>Email: {$usuarioSeleccionado["email"]}</p>";
+
     foreach ($resultado as $idade) {
−
            echo "<p><a href='listaUsuarios.php'>Volver á lista de usuarios</a></p>";
+
         echo "<li>$idade anos</li>";
−
        } else {
 
−
            echo "<p>Usuario non encontrado.</p>";
 
−
        }
 
−
     } else {
 
−
         echo "<p>ID de usuario non especificado.</p>";
 
 
     }
 
     }
−
     ?>
+
 
 +
     echo '</ul>';
 +
} else {
 +
    echo '<h2>Ningunha idade cumpre a condición</h2>';
 +
}
 +
?>
 
</body>
 
</body>
 
</html>
 
</html>
−
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
−
 
+
<br> -- [[Usuario:angelfg|Ángel D. Fernández González]] -- (2026).
−
<br> -- [[Usuario:angelfg|Ángel D. Fernández González]] -- (2025).
 

Revisión del 17:02 13 sep 2026

Introdución

  • Cando programamos pode darse o caso de que teñamos código (en forma de funcións, variables, constantes, clases ou bloques de código) que teñamos que utilizar en moitas páxinas distintas.
  • Nestes casos é conveniente ter o código gardado nun arquivo separado e poder incorporalo cando o necesitemos.
  • En PHP podemos facelo coas construcións da linguaxe: include, include_once, require e require_once.


include

  • Sintaxe:
include '[path/]arquivo.php';
  • A sentenza include inclúe e avalía o arquivo especificado.
  • O camiño pode ser absoluto ou relativo. Para evitar problemas coa resolución de rutas é recomendable construír a ruta tomando como referencia o directorio do arquivo PHP actual mediante a constante máxica __DIR__.
Por exemplo:
include __DIR__ . '/utilidades/arquivo.php';
  • Antigamente empregábase con frecuencia a extensión .inc.php para este tipo de arquivos, pero actualmente podemos empregar directamente a extensión .php.
  • O código PHP do arquivo incluído debe atoparse entre etiquetas PHP.
Se o arquivo contén unicamente código PHP, é recomendable empregar a etiqueta de apertura <?php e omitir a etiqueta de peche ?> ao final do arquivo.
Desta forma evitamos que espazos ou saltos de liña situados accidentalmente despois da etiqueta de peche produzan unha saída non desexada.
  • Vexamos un exemplo:
Arquivo: FuncionsExternas.php
 1 <?php
 2 
 3 /**
 4  * Crea un array cun número específico de elementos inicializados a null.
 5  *
 6  * @param int $numElementos Número de elementos que terá o array.
 7  *
 8  * @return array Array co número de elementos indicado, todos con valor null.
 9  */
10 function crearArray(int $numElementos): array
11 {
12     $array = [];
13 
14     for ($cont = 0; $cont < $numElementos; $cont++) {
15         $array[$cont] = null;
16     }
17 
18     return $array;
19 }
Arquivo: ReutilizandoCodigo.php
 1 <!DOCTYPE html>
 2 <html lang="gl">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Exemplos de código PHP</title>
 6 </head>
 7 <body>
 8 <?php
 9 include __DIR__ . '/FuncionsExternas.php';
10 
11 $datos = crearArray(10);
12 
13 foreach ($datos as $clave => $dato) {
14     printf(
15         "Clave:%d - Valor:%s<br>",
16         $clave,
17         $dato === null ? 'Sen dato' : $dato
18     );
19 }
20 ?>
21 </body>
22 </html>
  • As funcións e clases definidas nun arquivo incluído teñen ámbito global.
  • No caso das variables, o arquivo incluído herda o ámbito do punto no que se realiza a inclusión.
Por exemplo, se facemos un include dentro dunha función, as variables definidas no arquivo incluído pertencerán ao ámbito desa función.
  • Cando fagamos unha aplicación con acceso a base de datos teremos que gardar información sensible, como datos de conexión.
É recomendable gardar este tipo de información nun arquivo situado fóra da ruta pública do servidor web.
Imaxinemos que o servidor web publica por defecto o cartafol:
/var/www/html
Poderiamos gardar a configuración, por exemplo, en:
/var/www/configuracions/informacionbd.php
Desta forma, coa configuración habitual do servidor web, ese arquivo non poderá solicitarse directamente mediante unha URL.


include_once

  • Sintaxe:
include_once '[path/]arquivo.php';
  • include_once ten o mesmo comportamento que include, pero PHP comproba se o arquivo xa foi incluído previamente. Se xa foi incluído, non o volve procesar.
  • Isto é especialmente útil cando o arquivo define funcións, clases ou constantes, xa que incluílo máis dunha vez podería provocar erros por declaracións duplicadas.
  • Debemos escoller entre include e include_once en función de se queremos permitir ou non que o mesmo arquivo sexa procesado máis dunha vez.
  • Pode darse o caso, por exemplo, cando facemos inclusións condicionais dentro dun if, de que un arquivo xa fose cargado previamente.
  • Os arquivos incluídos tamén poden utilizarse para gardar elementos comúns a varias páxinas web, como unha cabeceira, un menú ou un pé de páxina.
Desta forma, se necesitamos modificar un elemento común, soamente teremos que facelo nun único arquivo.
  • En PHP existe outra forma de organizar os elementos comúns empregando un modelo ou patrón MVC.
Podedes consultalo neste enlace da WIKI.


require

  • Sintaxe:
require '[path/]arquivo.php';
  • require fai o mesmo que include, pero existe unha diferenza importante cando non se pode cargar o arquivo:
  • include produce un aviso de tipo E_WARNING e a execución do script pode continuar.
  • require produce un erro de tipo Error. Se non se trata, a execución do script interrómpese.
  • Por este motivo empregaremos normalmente require cando o arquivo sexa imprescindible para que a aplicación poida funcionar.

Exemplo con include

 1 <!DOCTYPE html>
 2 <html lang="gl">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Exemplo con include</title>
 6 </head>
 7 <body>
 8 <?php
 9 include __DIR__ . '/FuncionsExternasNonExiste.php';
10 
11 echo 'Isto aparece porque include permite continuar a execución.';
12 ?>
13 </body>
14 </html>
Se o arquivo non existe, aparecerá un warning, pero a execución poderá continuar.

Exemplo con require

 1 <!DOCTYPE html>
 2 <html lang="gl">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Exemplo con require</title>
 6 </head>
 7 <body>
 8 <?php
 9 require __DIR__ . '/FuncionsExternasNonExiste.php';
10 
11 echo 'Esta instrución non chegará a executarse se o erro non é tratado.';
12 ?>
13 </body>
14 </html>
Neste caso, ao ser o arquivo obrigatorio, a execución interrómpese se non pode cargarse e o erro non é tratado.


require_once

  • Sintaxe:
require_once '[path/]arquivo.php';
  • Ten o mesmo comportamento que require, pero se o arquivo xa foi incluído previamente non se volverá incluír.
  • É especialmente útil cando:
  • o arquivo é obrigatorio para o funcionamento da aplicación;
  • non sabemos con certeza se xa foi cargado previamente;
  • o arquivo define funcións, clases ou constantes que non deben declararse máis dunha vez.
Resumo:
Sentenza O arquivo é obrigatorio Evita incluílo máis dunha vez
include Non Non
include_once Non Si
require Si Non
require_once Si Si


Configuración da visualización e rexistro de erros

  • Durante o desenvolvemento é importante detectar e corrixir erros, warnings e mensaxes de depreciación.
  • Nun servidor de produción, pola contra, non debemos amosar directamente os erros ao usuario, xa que poden revelar información interna da aplicación ou do servidor.

Entorno de desenvolvemento

  • Durante o desenvolvemento podemos pedir a PHP que informe de todos os erros:
error_reporting(E_ALL);
ini_set('display_errors', '1');
  • E_ALL indica que queremos recibir todos os erros, warnings, notices e mensaxes de depreciación configuradas por PHP.

Entorno de produción

  • Nun entorno de produción é recomendable non amosar os erros ao usuario e gardalos no rexistro do servidor.
Unha configuración típica no arquivo php.ini sería:
display_errors = Off
log_errors = On
error_reporting = E_ALL
  • Desta forma os erros seguirán rexistrándose, pero non se amosarán directamente na páxina web.

Máscaras de erros

  • PHP tamén permite combinar constantes de erros mediante operadores a nivel de bits.
Por exemplo:
// Erros, warnings e erros de análise.
error_reporting(E_ERROR | E_WARNING | E_PARSE);

// Todos os erros excepto E_NOTICE.
error_reporting(E_ALL & ~E_NOTICE);
Aínda que esta posibilidade existe, durante o desenvolvemento empregaremos normalmente:
error_reporting(E_ALL);

A través do arquivo .htaccess

  • Se PHP se executa como módulo de Apache e a configuración do servidor o permite, é posible modificar determinadas opcións de PHP mediante o arquivo .htaccess.
Por exemplo:
php_value error_reporting 2147483647
php_flag display_errors On
  • Esta forma de configuración non é válida para todas as formas de executar PHP.
Por exemplo, cando PHP se executa mediante CGI/FastCGI poden empregarse arquivos .user.ini para determinadas opcións de configuración.


Colocar arquivos sensibles

  • Veremos nas seguintes unidades que teremos que gardar información sensible en certos arquivos PHP, como os datos necesarios para conectarnos a unha base de datos.
  • Podemos definir esa información nun arquivo PHP, por exemplo informacionbd.php, e incorporalo mediante require ou require_once nas páxinas que necesiten utilizalo.
  • Para evitar que este tipo de arquivos poidan solicitarse directamente desde o navegador, é recomendable situalos fisicamente fóra do DocumentRoot do servidor web.
Por exemplo, se Apache publica:
/var/www/html
podemos gardar o arquivo de configuración en:
/var/www/configuracions/informacionbd.php
  • Ademais, debemos:
  • configurar correctamente os permisos do arquivo;
  • evitar gardar contrasinais ou credenciais en repositorios públicos;
  • permitir o acceso unicamente ao usuario ou servizo que realmente o necesite.


Exercicios propostos

  • Exercicio 1: Define nun arquivo externo dentro dun cartafol de nome utilidades dúas funcións:
  • unha función que, a partir dunha cadea, engada dita cadea a un array se non existe previamente;
  • outra función que, dado un array, devolva unha copia do array recibido.
Xera unha páxina que faga uso das funcións do arquivo anterior. O arquivo é obrigatorio para o funcionamento da páxina.


  • Exercicio 2: Define nun arquivo externo de nome utilidades2.php, dentro do cartafol utilidades, as seguintes constantes:
  • NUM_ELEMENTOS igual a 3;
  • IDADE_MAIOR igual a 18.
Crea tamén unha función que, dado un array numérico, comprobe que o número de elementos do array sexa superior a NUM_ELEMENTOS.
Se non se cumpre esta condición, a función debe devolver false.
En caso contrario, debe devolver un array cos elementos que sexan maiores que IDADE_MAIOR. Se ningún elemento cumpre a condición, debe devolver false.
Crea unha páxina de exemplo de uso da función anterior, tendo en conta que a páxina pode xerarse dinamicamente e non sabemos se o arquivo foi incluído previamente. A páxina necesita cargar obrigatoriamente o arquivo utilidades2.php.


Solución Exercicios propostos

  • Solución Exercicio 1
Páxina utilidades/utilidades1.php
<?php

/**
 * Engade unha cadea ao array se non existe xa.
 *
 * @param array  &$array Array onde se engadirá a cadea.
 * @param string $cadea  Cadea de texto a engadir.
 *
 * @return void
 */
function engadirCadeaAoArray(array &$array, string $cadea): void
{
    if (!in_array($cadea, $array, true)) {
        $array[] = $cadea;
    }
}

/**
 * Devolve unha copia dun array.
 *
 * En PHP os arrays asígnanse por valor. Polo tanto, devolver o array
 * permite obter unha copia que pode modificarse sen alterar o array orixinal.
 *
 * @param array $array Array que se quere copiar.
 *
 * @return array Copia do array recibido.
 */
function copiarArray(array $array): array
{
    return $array;
}
Páxina exercicio1_include.php
<!DOCTYPE html>
<html lang="gl">
<head>
    <meta charset="UTF-8">
    <title>Exemplo PHP en Galego</title>
</head>
<body>
<?php
require __DIR__ . '/utilidades/utilidades1.php';

$meuArray = [];

// Engadir cadeas ao array.
engadirCadeaAoArray($meuArray, 'Ola');
engadirCadeaAoArray($meuArray, 'Mundo');
engadirCadeaAoArray($meuArray, 'Ola'); // Xa existe e non se engadirá de novo.

// Copiar o array.
$copiaArray = copiarArray($meuArray);

echo '<h2>Array orixinal:</h2>';
echo '<pre>';
print_r($meuArray);
echo '</pre>';

echo '<h2>Copia do array:</h2>';
echo '<pre>';
print_r($copiaArray);
echo '</pre>';
?>
</body>
</html>


  • Solución Exercicio 2
Páxina utilidades/utilidades2.php
<?php

const NUM_ELEMENTOS = 3;
const IDADE_MAIOR = 18;

/**
 * Comproba as idades dun array e devolve os elementos que superen un límite.
 *
 * @param array $array Array de números (idades) a comprobar.
 *
 * @return array|false Devolve un array cos elementos maiores que IDADE_MAIOR
 *                     ou false se non se cumpren as condicións.
 */
function comprobarIdade(array $array): array|false
{
    $elementosCumpridos = [];

    if (count($array) <= NUM_ELEMENTOS) {
        return false;
    }

    foreach ($array as $idade) {
        if ($idade > IDADE_MAIOR) {
            $elementosCumpridos[] = $idade;
        }
    }

    return $elementosCumpridos !== [] ? $elementosCumpridos : false;
}
Páxina exercicio2_include.php
<!DOCTYPE html>
<html lang="gl">
<head>
    <meta charset="UTF-8">
    <title>Exemplo PHP en Galego</title>
</head>
<body>
<?php
require_once __DIR__ . '/utilidades/utilidades2.php';

$idades = [2, 62, 2, 2, 2]; // Soamente 62 cumpre a condición.

$resultado = comprobarIdade($idades);

if ($resultado !== false) {
    echo '<h2>Idades que cumpren a condición:</h2>';
    echo '<ul>';

    foreach ($resultado as $idade) {
        echo "<li>$idade anos</li>";
    }

    echo '</ul>';
} else {
    echo '<h2>Ningunha idade cumpre a condición</h2>';
}
?>
</body>
</html>


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