Ir para o conteúdo

SELECT, INSERT, UPDATE & DELETE

Seleccionar, inserir, alterar e eliminar dados de uma base de dados MySQL com PHP.

Atenção: a forma como comentei as páginas não é aconselhável, apenas o fiz para que toda a gente pudesse perceber as coisas.

-- phpMyAdmin SQL Dump
-- version 3.3.9
-- http://www.phpmyadmin.net
--
-- Máquina: localhost
-- Data de Criação: 03-Jun-2011 às 20:09
-- Versão do servidor: 5.5.8
-- versão do PHP: 5.3.5

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

--
-- Base de Dados: `teste`
--
CREATE DATABASE `teste` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `teste`;

-- --------------------------------------------------------

--
-- Estrutura da tabela `tabela1`
--

CREATE TABLE IF NOT EXISTS `tabela1` (
  `campo1` int(11) NOT NULL AUTO_INCREMENT,
  `campo2` char(32) NOT NULL,
  `campo3` varchar(15) NOT NULL,
  `campo4` text NOT NULL,
  `campo5` enum('valor1','valor2') NOT NULL,
  `campo6` set('valor1','valor2','valor3') NOT NULL,
  `campo7` tinyint(1) NOT NULL,
  `campo8` datetime NOT NULL,
  PRIMARY KEY (`campo1`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='Tabela 1' AUTO_INCREMENT=11 ;

--
-- Extraindo dados da tabela `tabela1`
--

INSERT INTO `tabela1` (`campo1`, `campo2`, `campo3`, `campo4`, `campo5`, `campo6`, `campo7`, `campo8`) VALUES
(1, '01773a8a11c5f7314901bdae5825a190', 'valor', 'valor', 'valor1', 'valor1,valor2,valor3', 0, '2011-06-03 21:02:05'),
(2, '01773a8a11c5f7314901bdae5825a190', 'valor', 'valor', 'valor2', 'valor1,valor2,valor3', 0, '2011-06-03 21:03:22'),
(3, '01773a8a11c5f7314901bdae5825a190', 'valor', 'valor', 'valor1', 'valor1,valor2,valor3', 1, '2011-06-03 21:03:36'),
(4, '01773a8a11c5f7314901bdae5825a190', 'valor', 'valor', 'valor1', '', 0, '2011-06-03 21:04:00'),
(5, '01773a8a11c5f7314901bdae5825a190', 'valor', 'valor', 'valor1', 'valor1,valor2', 0, '2011-06-03 21:04:10'),
(6, '01773a8a11c5f7314901bdae5825a190', 'valor', 'valor', 'valor1', 'valor1,valor3', 0, '2011-06-03 21:04:19'),
(7, '01773a8a11c5f7314901bdae5825a190', 'valor', 'valor', 'valor1', 'valor2,valor3', 0, '2011-06-03 21:04:28'),
(8, '01773a8a11c5f7314901bdae5825a190', 'valor', 'valor', 'valor2', 'valor2', 1, '2011-06-03 21:04:58'),
(9, '01773a8a11c5f7314901bdae5825a190', 'valor', 'valor', 'valor2', 'valor1,valor2,valor3', 1, '2011-06-03 21:05:12'),
(10, '01773a8a11c5f7314901bdae5825a190', 'valor', 'valor', 'valor2', 'valor2', 0, '2011-06-03 21:05:48');
config.php
<?php
/**
 * @author  Luis Coutinho <Luis@lfscoutinho.net>
 * @date    04/06/2011
 */
session_start();

// Modo DEBUG (TRUE = mostrar; FALSE = não mostrar)

define('DEBUG', TRUE);

// Configuração da base de dados

define('DB_HOST', 'localhost'); // Host da base de dados
define('DB_PORT', '3306');  // Porta da base de dados
define('DB_SGBD', 'mysql'); // SGBD (mysql, mssql, etc)
define('DB_USER', 'root');  // Nome do utilizador da base de dados
define('DB_PASS', '');      // Senha do utilizadors da base de dados
define('DB_NAME', 'teste'); // Nome da base de dados

// Tabelas da base de dados

# tabela1
define('TBL1',  'tabela1'); // Nome da tabela
define('TBL1_CMP1', 'campo1');  // Nome do campo 1 da tablela "TBL1" (tabela1)
define('TBL1_CMP2', 'campo2');  // Nome do campo 2 da tablela "TBL1" (tabela1)
define('TBL1_CMP3', 'campo3');  // Nome do campo 3 da tablela "TBL1" (tabela1)
define('TBL1_CMP4', 'campo4');  // Nome do campo 4 da tablela "TBL1" (tabela1)
define('TBL1_CMP5', 'campo5');  // Nome do campo 5 da tablela "TBL1" (tabela1)
define('TBL1_CMP6', 'campo6');  // Nome do campo 6 da tablela "TBL1" (tabela1)
define('TBL1_CMP7', 'campo7');  // Nome do campo 7 da tablela "TBL1" (tabela1)
define('TBL1_CMP8', 'campo8');  // Nome do campo 8 da tablela "TBL1" (tabela1)

// Dados da sessão

define('SESS_TOKEN', 'token');  // Token para proteger os formulários
funcoes.php
<?php

    /**
     * @author  Luis Coutinho <Luis@lfscoutinho.net>
     * @date    04/06/2011
     */

    // Função para ligar à base de dados
    function conectar() {
        // Data source name
        $dsn = DB_SGBD;
        $dsn.= ':host='     . DB_HOST;
        $dsn.= ';port='     . DB_PORT;
        $dsn.= ';dbname='   . DB_NAME;

        // Cria a conexão à base de dados
        $con = new PDO( $dsn, DB_USER, DB_PASS );
        $con->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

        // Retorna a conexão criada
        return $con;
    }

    // Função para tratar da excepções relativas à base de dados
    function pdoException( $e ) {
        // Se a constante "DEBUG" tiver com o valor "TRUE",
        // mostra o que aconteceu (mensagem, ficheiro e linha)
        if( DEBUG ) {
            $msg = 'Mensagem: '         . $e->getMessage();
            $msg.= "ntt<br />Ficheiro: "    . $e->getFile();
            $msg.= "ntt<br />Linha: "   . $e->getLine();

            // Mostra a mensagem com os dados da excepção e termina a
            // execução do script
            exit( $msg );
        }

        $msg = 'Ocorreu um erro ao conectar à nossa base de dados. ';
        $msg.= 'Por favor, tente mais tarde.';

        // Mostra a mensagem indicada e termina a execução do script
        exit( $msg );
    }

    // Função utilizada para retornar os erros editados
    function gerarErros( $erros ) {
        // Se existirem erros ...
        if( $erros ) {
            $html = '';

            foreach( $erros as $erro ) {
                $html.= "nttt<p>$erro</p>";
            }
            return $html;

        } else {
            return false;
        }
    }

    // Função que gera um token, atribui-o à sessão e retorna-o
    function gerarToken() {
        // 1º Gera um número aleatório
        // 2º Gera um ID único, cujo prefixo é o número gerado aleatoriamente
        // 3º Calcula um hash MD5 do ID único gerado anteriormente
        $token = md5( uniqid( rand() ) );

        // Atribui o token à sessão
        $_SESSION[SESS_TOKEN] = $token;

        // Retorna o token
        return $token;
    }

    // Função equivalente à "array_key_exists", mas que permite ter como 
    // argumento um array
    function array_keys_exist( $oQue, $onde) {
        // Para cada chave do array $oQue, verifica se ela existe no array $onde.
        // Se houver alguma chave do array $oQue que não exista no array $onde,
        // a função retorna imediatamente "FALSE". Caso contrário, se todas elas
        // existirem, retorna "TRUE";
        foreach( $oQue as $chave ) {
            if( ! array_key_exists( $chave, $onde ) ) {
                return false;
            }
        }
        return true;
    }
index.php
<?php

    /**
     * @author  Luis Coutinho <Luis@lfscoutinho.net>
     * @date    04/06/2011
     */

    require'config.php';    // Requer o ficheiro config.php
    require'funcoes.php';   // Requer o ficheiro funcoes.php

    // Todo o site vai correr pela página index.php; Esta constante vai-nos
    // permitir saber se estamos ou não a utilizar esta página para ver as outras
    define('INDEX', TRUE);

?>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <meta name="author" content="Luis Coutinho <Luis@lfscoutinho.net>" />
        <title>SELECCIONAR, INSERIR, EDITAR E ELIMINAR</title>
    </head>
    <body>

        <p><a href="?pag=sel">Seleccionar</a> <a href="?pag=ins">Inserir</a></p>

        <?php
            // Lista branca com as páginas que podem ser visualizadas
            $paginas    = array( 'ini', 'ins', 'edi', 'eli' );

            // Verifica se existe a chave "pag" no array $_GET e se o seu valor
            // está na lista branca (páginas que podem ser visualizadas)
            if( isset( $_GET['pag'] ) && in_array( $_GET['pag'], $paginas ) ) {
                switch ( $_GET['pag'] ) {
                    case 'sel'  :
                        $pagina = 'seleccionar.php';
                        break;
                    case 'ins'  :
                    case 'edi'  :
                        $pagina = 'guardar.php';
                        break;
                    case 'eli'  :
                        $pagina = 'eliminar.php';
                        break;
                }
            } else {
                $pagina = 'seleccionar.php';
            }
            require $pagina; // Requer o ficheiro a ser visualizado
        ?>
    </body>
</html>
seleccionar.php
<?php
    /**
     * @author  Luis Coutinho <Luis@lfscoutinho.net>
     * @date    04/06/2011
     */

    // Verifica se a constante INDEX está definida. Se não estiver, significa
    // que o utilizador está a aceder a esta página directamente
    if( ! defined( 'INDEX' ) ) {
        die( _( 'Não pode aceder directamente a esta página' ) );
    }

    // Cria a consulta SQL
    $sql = 'SELECT %s, %s, %s, %s, %s, %s, %s, %s FROM %s';
    $sql = sprintf( $sql, TBL1_CMP1, TBL1_CMP2, TBL1_CMP3, TBL1_CMP4,
            TBL1_CMP5, TBL1_CMP6, TBL1_CMP7, TBL1_CMP8, TBL1 );
    try {
        // Liga à base de dados
        $con    = conectar();

        // Faz a consulta à base de dados
        $query  = $con->query( $sql, PDO::FETCH_ASSOC );

        // Coloca o resultado em uma variável para mostrar onde quiser e evitar
        // misturar muito PHP com HTML
        $html   = '';

        foreach( $query as $row ) {
            $html.= "nttt<tr>";
            $html.= "ntttt<td>";
            $html.= '<a href="?pag=edi&id=%s"><img src="edi.png" height="16" width="16" border="0" /></a>';
            $html.= '<a href="?pag=eli&id=%s"><img src="eli.png" height="16" width="16" border="0" /></a>';
            $html.= '</td>';
            $html.= "ntttt<td>%s</td>";
            $html.= "ntttt<td>%s</td>";
            $html.= "ntttt<td>%s</td>";
            $html.= "ntttt<td>%s</td>";
            $html.= "ntttt<td>%s</td>";
            $html.= "ntttt<td>%s</td>";
            $html.= "ntttt<td>%s</td>";
            $html.= "ntttt<td>%s</td>";
            $html.= "nttt</tr>";

            // Converte os caracteres aplicáveis em entidades html, prevenindo
            // que sejam executados código html/javascript
            $row[TBL1_CMP4] = htmlentities( $row[TBL1_CMP4], ENT_QUOTES, 'UTF-8' );

            // Se não tiver seleccionad nenhum valor, mostra "nenhum"
            $row[TBL1_CMP6] = empty( $row[TBL1_CMP6] )  ? '<s>nenhum</s>'   : $row[TBL1_CMP6];

            // Se o valor for 1, mostra "sim", caso contrário mostra "não"
            $row[TBL1_CMP7] = $row[TBL1_CMP7]       ? 'sim'         : 'não';

            // Mostra a hora e data no formato português
            $row[TBL1_CMP8] = date( 'H:i d-m-Y', strtotime( $row[TBL1_CMP8] ) );

            // Coloca os valores na variável
            $html = sprintf( $html, $row[TBL1_CMP1], $row[TBL1_CMP1], $row[TBL1_CMP1],
                        $row[TBL1_CMP2], $row[TBL1_CMP3], $row[TBL1_CMP4],
                        $row[TBL1_CMP5], $row[TBL1_CMP6], $row[TBL1_CMP7],
                        $row[TBL1_CMP8] );
        }

        // Fecha a conexão à base de dados
        $con = NULL;
    } catch ( PDOException $e ) {
        pdoException( $e );
    }
?>
        <table>
            <thead>
                <tr>
                    <th>&nbsp;</th>
                    <th>Cmp 1</th>
                    <th>Cmp 2</th>
                    <th>Cmp 3</th>
                    <th>Cmp 4</th>
                    <th>Cmp 5</th>
                    <th>Cmp 6</th>
                    <th>Cmp 7</th>
                    <th>Cmp 8</th>
                </tr>
            </thead>
            <?php echo $html // Imprime o resultado ?>

            <tfoot>
                <tr>
                    <th>&nbsp;</th>
                    <th>Cmp 1</th>
                    <th>Cmp 2</th>
                    <th>Cmp 3</th>
                    <th>Cmp 4</th>
                    <th>Cmp 5</th>
                    <th>Cmp 6</th>
                    <th>Cmp 7</th>
                    <th>Cmp 8</th>
                </tr>
            </tfoot>
        </table>
guardar.php
<?php
    /**
     * @author  Luis Coutinho <Luis@lfscoutinho.net>
     * @date    04/06/2011
     */
    // Verifica se a constante INDEX está definida. Se não estiver, significa
    // que o utilizador está a aceder a esta página directamente
    if( ! defined( 'INDEX' ) ) {
        die( _( 'Não pode aceder directamente a esta página' ) );
    }

    // Nome dos campos do formulário para verificar se é o original.
    // Repara que não coloquei o "cmp6", pois no caso dos checkboxes e dos
    // selects com a propriedade multiple, quando nenhum valor é checkado, não
    // aparece nada no array $_POST, ao contrário dos inputs do tipo text que
    // aparecem como strings vazias.
    $campos = array( 'token', 'cmp1', 'cmp2', 'cmp3', 'cmp4', 'cmp5', 
             'cmp7', 'guardar' );

    // 1º Se o array $_POST tiver chaves, então significa que o formulário foi submetido
    // 2º Se os valores do array $campos existirem nas chaves do array $_POST, 
    // então significa que o formulário não foi alterado (aqui não uso 
    // array_values( $campos ) === array_keys( $_POST ), por causa dos inputs
    // checkboxes e selects com a propriedade multiple, daí ter criado a função array_keys_exist()
    // 3º Se a chave SESS_TOKEN existir, significa que o utilizador está ou
    // esteve no nosso site e ainda não fechou o browser
    // 4º Se a chave SESS_TOKEN for idêntica (igual e do mesmo tipo) à enviada
    // no formulário, garante-nos que enviou o formulário através do nosso site,
    // porque sempre que abre/recarrega/submete a página/formulário é gerado um novo token
    if( $_POST &&
        array_keys_exist( array_values( $campos ) , $_POST ) &&
        isset( $_SESSION[SESS_TOKEN] ) &&
        $_SESSION[SESS_TOKEN] === $_POST['token'] ) {

        /**
         * Validações
         */
        // Limpamos o array campos, pois vamos utilizá-lo para guardar os dados
        // validados correctamente e/ou os erros
        $campos = array();

        // Verifica se é para criar um registo novo ou para editar
        $campo = trim( $_POST['cmp1'] );

        if( $campo ) {
            // Verifica se o valor é um número e é maior que "0" (zero)
            if( ctype_digit( $campo ) && $campo > 0 ) {
                $campos['cmp1'] = $campo;
            } else {
                $campos['erros']['cmp1'] = 'O registo indicado não existe.';
            }
        }

        // Remove os espaços em branco do início e do fim da string, atribui o
        // resultado à variável $campo e verifica se tem, pelo menos, 1 caracter.
        // Também existe a função empty(), no entanto, caso o valor indicado
        // seja "0" (zero), esta função retorna FALSE.
        $campo = trim( $_POST['cmp2'] );

        if( strlen( $campo ) ) {
            $campos['cmp2'] = md5( $campo ); // Cria um hash MD5
        } else {
            $campos['erros']['cmp2'] = _('O "Campo 2" tem de ter um valor.');
        }

        // Verifica se só foram introduzidas letras, apóstrofos ('), hifens (-)
        // e espaços. Atenção esta expressão regular não é a melhor, esta permite
        // que sejam introduzidos alguns caracteres que os nomes não têm, o melhor
        // é colocar apenas os caracteres aceites.
        // A melhor forma é utilizar função ctype_alpha. No entanto, para que esta
        // funcione bem (aceitando palavras acentuadas) é necessário definir o local.
        $campo      = trim( $_POST['cmp3'] );
        $pattern    = '/^[a-zA-ZÀ-ÿ'- ]{1,15}$/';

        if( $campo && preg_match( $pattern, $campo ) ) {
            $campos['cmp3'] = $campo;
        } else {
            $campos['erros']['cmp3'] = _('O "Campo 3"  pode conter letras e espaços.');
        }

        // Verifica se o campo tem, no mínimo, 1 caracter e se tem, no máximo,
        // 65535 caracteres (máximo que o campo do tipo TEXT aceita).
        $campo = trim( $_POST['cmp4'] );

        if( $campo && strlen( $campo ) < 65535 ) {
            $campos['cmp4'] = $campo;
        } else {
            $campos['erros']['cmp4'] = _('O "Campo 4" tem de ser preenchido.');
        }

        // Verifica se o valor introduzido é permitido
        $campo = $_POST['cmp5'];
        $valores = array( 'valor1', 'valor2' ); // Lista branca

        if( in_array( $campo, $valores ) ) {
            $campos['cmp5'] = $campo;
        } else {
            $campos['erros']['cmp5'] = _('O valor do "Campo 5" não é permitido.');
        }

        // Verifica se existe o "cmp6" no array $_POST, isto é, verifica se
        // foi checkado algum dos checkboxes do fieldset "Campo 6"
        if( isset( $_POST['cmp6'] ) ) {
            $campo = $_POST['cmp6'];

            // Verifica se o "Campo 6" é um array
            if( is_array( $campo ) ) {
                // Lista branca com os valores do "Campo 6"
                $valores = array( 'valor1', 'valor2', 'valor3' );

                // Para cada checkbox seleccionada, verifica se o valor é permitido
                foreach( $campo as $valor ) {
                    if( ! in_array( $valor, $valores ) ) {
                        $campos['erros']['cmp6'] = _('Os valores indicados no "Campo 6" não são permitidos.');
                        break;
                    }
                }

                // Se não existir a chave "cmp6" no array $campos['erros'],
                // então significa que todos os valores indicados são permitidos
                // e colocam-se esses valores numa string separados por uma "," (vírgula)
                if( ! isset( $campos['erros']['cmp6'] ) ) {
                    $campos['cmp6'] = implode( ',', $campo );
                }
            } else {
                $campos['erros']['cmp6'] = _('O valor indicado no "Campo 6" não é válido.');
            }
        } else {
            $campos['cmp6'] = '';
        }

        // Verifica se o valor escolhido no "Campo 7" é permitido
        $valores = array( '0', '1' ); // Lista branca

        if( in_array( $_POST['cmp7'], $valores ) ) {
            $campos['cmp7'] = $_POST['cmp7'];
        } else {
            $campos['erros']['cmp7'] = _('O valor indicado no "Campo 7" não é permitido.');
        }

        // Verifica se campos foram validados correctamente
        if( ! isset( $campos['erros'] ) ) {
            if( ! isset( $campos['cmp1'] ) ) { // Inserir
                // Cria a consulta SQL
                $sql = 'INSERT INTO %s (%s, %s, %s, %s, %s, %s, %s)';
                $sql.= 'VALUES(:cmp2, :cmp3, :cmp4, :cmp5, :cmp6, :cmp7, NOW())';

                $sql = sprintf( $sql, TBL1, TBL1_CMP2, TBL1_CMP3, TBL1_CMP4,
                        TBL1_CMP5, TBL1_CMP6, TBL1_CMP7, TBL1_CMP8);

                try {
                    // Liga à base de dados
                    $con = conectar();

                    // Prepara a instrução SQL
                    $stmt = $con->prepare( $sql );

                    // Atribui os valores correspondentes aos parâmetros da consulta
                    $stmt->bindValue( ':cmp2', $campos['cmp2'], PDO::PARAM_STR );
                    $stmt->bindValue( ':cmp3', $campos['cmp3'], PDO::PARAM_STR );
                    $stmt->bindValue( ':cmp4', $campos['cmp4'], PDO::PARAM_STR );
                    $stmt->bindValue( ':cmp5', $campos['cmp5'], PDO::PARAM_STR );
                    $stmt->bindValue( ':cmp6', $campos['cmp6'], PDO::PARAM_STR );
                    $stmt->bindValue( ':cmp7', $campos['cmp7'], PDO::PARAM_INT );

                    // Executa a consulta
                    $stmt->execute();

                    // Verifica se existem linhas afectadas pela instrução
                    if( $stmt->rowCount() ) {
                        $html = _('Registo efectuado com sucesso.');
                    } else {
                        $html = _('Ocorreu um problema ao registar na nossa base de dados.<br/>Por favor, tente novamente.');
                    }

                    // Fecha o cursor
                    $stmt->closeCursor();

                    // Fecha a conexão à base de dados
                    $con = NULL;
                } catch ( PDOException $e ) {
                    pdoException( $e );
                }
            } else { // Adicionar
                // Cria a consulta
                $sql = 'SELECT COUNT(*) AS n FROM %s WHERE %s = :cmp1';
                $sql = sprintf( $sql, TBL1, TBL1_CMP1 );

                try {
                    // Cria a ligação à base de dados
                    $con    = conectar();

                    // Prepara a instrução SQL
                    $stmt   = $con->prepare( $sql );

                    // Atribui os valores aos parâmetros
                    $stmt->bindValue( ':cmp1', $campos['cmp1'], PDO::PARAM_INT );

                    // Executa a instrução SQL
                    $stmt->execute();

                    // Coloca o resultado da consulta na variável $result
                    $result = $stmt->fetch( PDO::FETCH_ASSOC );

                    // Fecha o cursor do
                    $stmt->closeCursor();

                    // Verifica se existe um e apenas um registo com o id indicado,
                    // se não existir nenhum ou mais, algo de errado aconteceu
                    if( $result['n'] === '1' ) {
                        // Cria a consulta SQL
                        $sql = 'UPDATE %s SET %s = :cmp2, %s = :cmp3, %s = :cmp4,';
                        $sql.= '%s = :cmp5, %s = :cmp6, %s = :cmp7 WHERE %s = :cmp1';
                        $sql = sprintf( $sql, TBL1, TBL1_CMP2, TBL1_CMP3, TBL1_CMP4,
                                TBL1_CMP5, TBL1_CMP6, TBL1_CMP7,
                                TBL1_CMP1 );

                        // Prepara a instrução SQL
                        $stmt = $con->prepare( $sql );

                        // Atribui os valores correspondentes aos parâmetros da consulta
                        $stmt->bindValue( 'cmp2', $campos['cmp2'], PDO::PARAM_STR );
                        $stmt->bindValue( 'cmp3', $campos['cmp3'], PDO::PARAM_STR );
                        $stmt->bindValue( 'cmp4', $campos['cmp4'], PDO::PARAM_STR );
                        $stmt->bindValue( 'cmp5', $campos['cmp5'], PDO::PARAM_STR );
                        $stmt->bindValue( 'cmp6', $campos['cmp6'], PDO::PARAM_STR );
                        $stmt->bindValue( 'cmp7', $campos['cmp7'], PDO::PARAM_STR );
                        $stmt->bindValue( 'cmp1', $campos['cmp1'], PDO::PARAM_INT );

                        // Executa a instrução
                        $stmt->execute();

                        // Verifica se existem linhas afectadas pela instrução
                        if( $stmt->rowCount() ) {
                            $html = _('Registo editado com sucesso.');
                        } else {
                            $html = _('O registo indicado não existe.');
                        }

                        // Fecha o cursor
                        $stmt->closeCursor();

                        // Fecha a conexão à base de dados
                        $con = NULL;
                    }
                } catch ( PDOException $e ) {
                    pdoException( $e );
                }
            }
        } else {
            $html = gerarErros( $campos['erros'] );
        }
    }

    // Verifica se existe a variável $html e mostra-a
    if( isset( $html ) ) {
        echo $html;
    }
?>
        <form action="" method="post">
            <input type="hidden" name="token" value="<?php echo gerarToken() ?>" />
            <input type="hidden" name="cmp1" value="<?php if ( isset( $_GET['id'] ) ) echo $_GET['id'] ?>" />
            <input type="text" id="cmp2" name="cmp2" /> Campo 2<br />
            <input type="text" id="cmp3" name="cmp3" /> Campo 3<br />
            <input type="text" id="cmp4" name="cmp4" /> Campo 4<br />
            <select id="cmp5" name="cmp5">
                <option value="valor1">Valor 1</option>
                <option value="valor2">Valor 2</option>
            </select> Campo 5<br />
            <fieldset>
            <legend>Campo 6</legend>
            <input type="checkbox" id="cmp6-1" name="cmp6[]" value="valor1" /> Valor 1<br />
            <input type="checkbox" id="cmp6-2" name="cmp6[]" value="valor2" /> Valor 2<br />
            <input type="checkbox" id="cmp6-3" name="cmp6[]" value="valor3" /> Valor 3<br />
            </fieldset>
            <fieldset>
            <legend>Campo 7</legend>
            <input type="radio" id="cmp7-1" name="cmp7" value="0" checked="checked" /> Valor 1<br />
            <input type="radio" id="cmp7-2" name="cmp7" value="1" /> Valor 2<br />
            </fieldset>
            <input type="submit" id="guardar" name="guardar" value="Guardar" />
        </form>
eliminar.php
<?php
    /**
     * @author  Luis Coutinho <Luis@lfscoutinho.net>
     * @date    04/06/2011
     */
    // Verifica se a constante INDEX está definida. Se não estiver, significa
    // que o utilizador está a aceder a esta página directamente
    if( ! defined( 'INDEX' ) ) {
        die( _( 'Não pode aceder directamente a esta página' ) );
    }

    // Verifica se foi indicado o id, se é um número inteiro e maior que "0" (zero)
    if( isset( $_GET['id'] ) && ctype_digit( $_GET['id'] ) && $_GET['id'] > 0 ) {
        // Cria a consulta SQL
        $sql = 'DELETE FROM %s WHERE %s = :cmp1';
        $sql = sprintf( $sql, TBL1, TBL1_CMP1 );

        try {
            // Liga à base de dados
            $con    = conectar();

            // Prepara a instrução SQL
            $stmt   = $con->prepare( $sql );

            // Atribui o valor correspondente a :nome
            $stmt->bindValue( ':cmp1', $_GET['id'], PDO::PARAM_INT );

            // Executa a consulta
            $stmt->execute();

            // Verifica se o número de linhas eliminado é maior que "0" (zero)
            if( $stmt->rowCount() ) {
                $html = 'Registo eliminado com sucesso.';
            } else {
                $html = 'O registo com o id indicado não existe.';
            }

            // Fecha o cursor
            $stmt->closeCursor();

            // Fecha a conexão à base de dados
            $con    = NULL;
        } catch ( PDOException $e ) {
            pdoException( $e );
        }
    } else {
        $html = 'O registo com o id indicado não existe.';
    }
?>
        <p><?php echo $html // Imprime o resultado ?></p>

O uso de constantes

Como podem reparar, no ficheiro config.php usei constantes, não só para definir os dados da ligação à base de dados, mas também do(s) nome(s) da(s) tabela(s) e dos respectivos campos. Este é um dos meus hábitos e faço-o pelo seguinte motivo: a qualquer momento posso mudar o nome de um campo. Deste modo, basta-me mudar o nome na constante, caso contrário teria que mudar em todas as minhas consultas.

Alguns podem pensar: "Ah... mas para pequenas coisas não é necessário"... Na minha opinião esse é um mau pensamento, porque um website nunca está terminado e o que hoje é pequeno, amanhã pode ser grande. E, atenção: este motivo pode acontecer por várias razões:

  • Porque a dada altura achamos que uma tabela/campo não tem o nome mais adequado.
  • Porque foi contratado uma/uma nova pessoa que só irá trabalhar com bases de dados e por qualquer motivo quer mudar o que está feito para algo que acha mais correcto.
  • Etc...

PHP Data Objects (PDO)

PDO é uma extensão que define uma interface leve e consistente para aceder a bases de dados em PHP, proporcionando uma camada de abstracção. Ou seja, rápido e facilmente se passa de uma base de dados MySQL para uma base de dados MSSQL, entre outras. Para além disso, também nos permite utilizar parâmetros nas consultas, aumentando assim os níveis de segurança do website.

A função isset()

Como é definida no Manual do PHP, a função isset() informa se uma variável foi iniciada ou não. Esta função é muito útil. Eu aconselho sempre o uso desta função sempre que não se tem a certeza que a variável foi inicializada.

Por exemplo, existem programadores/desenvolvedores que quando usam o sistema que eu usei ("rodar" o site todo através de uma página, neste caso index.php), em vez de verificarem se a variável que indica a página a ser visualizada foi iniciada e posteriormente usarem a switch(), preferem omitir um erro que é gerado quando a variável não é inicializada utilizando o @ ($var = @$\_GET\['var'\]). Esta uma má prática de desenvolvimento e que eu desaconselho vivamente.

A função gettext()

A função gettext() é a que nos permite internacionalizar os websites. Ou seja, disponibilizá-los em várias línguas. Quem se está a iniciar deve ter reparado nos caracteres _() e ter ficado a pensar para que servia... Essa é uma abreviatura para a função gettext().

Como aconselhei anteriormente a utilização de constantes para definir os nomes das tabelas e respectivos campos das bases de dados, aconselho o uso da desta função. Pois, hoje um site é para ser só em português, mas amanhã pode ser para ser em várias línguas. Logo, é melhor optar por acrescentar esses 3 caracterezinhos e caso se mude de planos, apenas é necessário fazer a tradução utilizando o POEdit, em vez de ter de mudar toda a estrutura do site e ainda fazer a tradução.

Listas brancas vs Listas negras

Para quem é novo em programação é provável que nunca tenha ouvido falar nisto. Por isso, vou tentar explicar o que é e a diferença entre as duas da forma mais simples.

Enquanto que uma lista branca é um conjunto de dados aceites/permitidos, uma lista negra é um conjunto de dados não aceites/permitidos. Ou seja, uma lista branca deve ser utilizada quando temos um número definido de dados que podem ser utilizados e uma lista negra quando temos um conjunto de dados que não podem ser utilizados.

Na prática, uma lista branca pode ser utilizada para verificar se o valor de um select/checkbox é permitido e uma lista negra para prevenir a utilização de palavrões.