Um curso de PHP gratuito, muito breve e direto. Aqui você pode aprender PHP e ainda tirar dúvidas nos comentários dos nossos artigos. Venha aprender PHP de graça.

Aprender PHP pode ser algo um pouco complexo até que o desenvolvedor iniciante tenha total habilidade para criar sua própria aplicação sem depender de frameworks ou bibliotecas externas. Por este motivo, venho escrevendo tudo o que sei sobre a linguagem no TEO (Todo Espaço Online) para que iniciantes não tenha tanta dificuldade na sua iniciação.

É claro que para aqueles que desejam aprender, livros irão ajudar bastante, mas aqui no TEO você poderá deixar sua opinião, tirar dúvidas, criticar, enfim, é a Internet e aqui você é quem manda.

Até o momento já escrevi mais de 50 aula, mas como o desenvolvimento nunca para, provavelmente aparecerão mais aulas ao longo do curso, portanto, salve este link nos seus favoritos e sempre de uma revisada aqui para ver se tem algo novo.

Observação: Fiz o mesmo com JavaScript em Venha aprender JavaScript de graça.

Sem mais delongas, abaixo deixo o link para todas as aulas já escritas até o momento.

Aprender PHP grátis

Seguem os links para que você possa aprender PHP de graça:

  • Introdução ao PHP – Aula 1 – Para iniciar nosso minicurso de PHP grátis, farei uma introdução ao PHP e explicarei como criar e executar seu primeiro arquivo em um servidor que roda PHP.
  • Aspas, comentários e echo em PHP – Aula 2 – Para dar continuidade em nossas aulas, vamos entender como exibir algo utilizando o comando echo em PHP. Também veremos como utilizar aspas adequadamente.
  • Variáveis em PHP – Aula 3 – Variáveis em PHP: continuando com nosso curso sobre PHP, hoje você vai aprender a criar e manipular variáveis, uma das partes mais utilizadas da linguagem.
  • Constantes em PHP – Aula 4 – Semelhantes às variáveis, constantes em PHP são objetos para reter e representar valores, porém, uma vez definidas, não podem ser modificadas. Saiba mais.
  • Tipos de dados em PHP – Aula 5 – Veja as diferenças entre os tipos de dados em PHP. Vamos falar sobre valores booleanos, inteiros, números de ponto flutuante, strings, arrays e demais.
  • Arrays em PHP – Aula 6 – Arrays em PHP são mapas que relacionam valores para chaves. É possível usá-los como arrays, listas, pilhas, filas e até mais. Entenda mais sobre os eles.
  • Operadores aritméticos em PHP – Aula 7 – Os operadores aritméticos em PHP são os mesmos que aprendemos no tempo da escola: mais, menos, divisão e subtração (+, -, /, -). Aprenda mais sobre eles.
  • Operadores de atribuição em PHP – Aula 8 – Operadores de atribuição em PHP são os que configuram o valor da direita para o operando da esquerda. Aprenda a utilizá-los, do básico ao avançado, agora.
  • Operadores de comparação em PHP – Aula 9 – Operadores de comparação em PHP servem para comparar se valores são iguais, diferentes, maiores ou menores, e assim por diante. Aprenda comparação em PHP.
  • Operador de controle de erros em PHP – Aula 10 – O operador de controle de erros em PHP é o @ (arroba). Se você precisa esconder algum erro, basta acioná-lo antes da expressão. Veja como é simples.
  • Operadores lógicos em PHP – Aula 11 – Operadores lógicos em PHP verificam comparações entre expressões que retornam valores verdadeiros e/ou falsos. Acesse e aprenda a utilizar lógica em PHP.
  • Operadores de Incremento e Decremento em PHP – Aula 12 – Operadores de Incremento e Decremento em PHP são dois sinais de mais (++) ou menos (–), que incrementam em 1 o valor da expressão. Saiba mais sobre eles.
  • Operador de execução em PHP – Aula 13 – O acento grave é um operador de execução em PHP, tudo o que estiver entre ` e `, é considerado como comando executado no servidor. Veja como utilizá-lo.
  • Operadores bit-a-bit em PHP – Aula 14 – Operadores bit-a-bit em PHP trabalham em um nível de abstração bem mais baixo, diretamente com a representação binária do valor. Saiba como utilizá-los.
  • If, else e elseif em PHP – Aula 15 – If, else e elseif em PHP são desvios condicionais para controlar o fluxo do código. Com eles é possível executar ações baseadas em condições. Aprenda mais.
  • Switch em PHP – Aula 16 – Switch em PHP é utilizado para desvios condicionais (assim como if, else e elseif). Com ele é possível executar ações baseadas em condições. Aprenda mais.
  • Laço While em PHP – Aula 17 – O laço while em PHP é bastante simples, enquanto a expressão avaliada for verdadeira (true) a ação é executada. Aprenda como utilizar while em PHP agora.
  • Laço do while em PHP – Aula 18 – O laço do while em PHP é utilizado para que uma ação seja executada enquanto um ação seja avaliada como verdadeira. Aprenda como isso funciona na prática.
  • Laço for em PHP – Aula 19 – For em PHP é utilizado para executar ações repetidas de acordo com três expressões: valor, expressão verdadeira e alteração do valor inicial. Saiba mais.
  • Laço foreach em PHP – Aula 20 – Foreach em PHP nos fornece uma opção para percorrer todas as chaves e valores de um array. Além disso, também funciona com objetos. Aprenda mais a respeito.
  • $_POST em PHP – Aula 21 – $_POST em PHP é uma variável superglobal que recebe dados do que é postado por formulários HTML que utilizam o método post. Aprenda a manipular tais dados.
  • $_GET em PHP – Aula 22 – $_GET em PHP é um array associativo de valores passados ao seu código pelo HTTP GET. Normalmente, links de nossas páginas dinâmicas utilizam $_GET. Confira.
  • $_COOKIES em PHP – Aula 23 – $_Cookies em PHP é uma forma de trocar dados entre o navegador e o servidor, colocado num arquivo criado no computador do cliente para manter sessões HTTP.
  • $_SESSION em PHP – Aula 24 – $_SESSION em PHP são sessões que permitem salvar dados ($variáveis) durante a visita do cliente. Os dados podem ser permanentes até o navegador ser fechado.
  • Datas em PHP – date, mktime, time – Aula 25 – Aprenda a trabalhar com datas em PHP utilizando as funções date, mktime e time. Você verá como criar datas em todos os formatos, nacionais e internacionais.
  • Como validar formulários em PHP – Aula 26 – Neste artigo, vamos ver como é simples validar formulários em PHP. Trataremos campos como email, URL, campos em branco, números e mais. Leia e aprenda.
  • Crie tabelas e bases de dados no phpMyAdmin – Aula 27 – Para iniciarmos com o PDO em PHP, devemos primeiro aprender a criar tabelas e bases de dados no phpMyAdmin – a forma mais simples para gerenciamento de BDs.
  • PDO em PHP – Aula 28 – PDO é uma classe que representa a conexão entre o PHP e a base de dados. Neste tutorial você vai aprender a manipular dados de BDs MySQL com a PDO Class.
  • Sistema de login simples com PHP – Aula 29 – Aprenda como criar um sistema de login simples com PHP. Vamos utilizar tudo o que você aprendeu até hoje em nossas aulas, como PDO, $_SESSION e formulários.
  • Expressões regulares em PHP – Aula 30 – Expressões regulares em PHP são uma forma de encontrar ou substituir trechos de texto em variáveis. Aprenda como manipular qualquer valor em seu código PHP.
  • Funções em PHP – Aula 31 – Funções em PHP são excelentes para criar trechos de código encapsulado e reutilizável para realizar pequenas e grandes tarefas em sua aplicação. Saiba mais.
  • Como criar classes em PHP – Aula 32 – Aprenda como criar classes em PHP e comece a criar seus programas com orientação a objetos. Essa é a primeira de muitas aulas sobre PHP Orientado a Objetos.
  • Herança e polimorfismo em PHP – Aula 33 – Veja como funciona herança e polimorfismo em PHP Orientado a Objetos. Crie subclasses (classes derivadas) que herdam propriedades e métodos de superclasses.
  • Abstração de Classes em PHP – Aula 34 – Abstração de Classes em PHP consiste em criar classes modelo para outras classes. Métodos abstratos deverão ser configurados nas subclasses. Saiba mais…
  • Membros de classes PHP – Na aula sobre membros de classes PHP, você vai aprender a utilizar constantes de classe e propriedades e métodos estáticos em superclasses e subclasses.
  • Associação, agregação e composição em classes PHP – Aula 36 – Em orientação a objetos, associação, agregação e composição referem-se à maneira como os objetos se relacionam entre si. Aprenda como isso funciona em PHP.
  • Métodos mágicos em classes PHP – Aula 37 – Métodos mágicos em PHP são métodos que são invocados quando tentamos utilizar ou manipular propriedades e métodos em classes e objetos. Veja como funciona.
  • Interfaces de Objetos em PHP – Aula 38 – Interfaces de Objetos em PHP são entidades que possuem métodos definidos sem corpo. Classes originadas dessa interface deverão implementar seus métodos.
  • __clone: Criando clones de objetos em PHP – Aula 39 – Veja como é simples criar clones de objetos PHP com “clone” e o método “__clone”. É uma excelente prática para facilitar sua vida enquanto desenvolvedor.
  • __autoload: Incluir classes automaticamente em PHP – Aula 40 – Crie uma função __autoload para carregar suas classes PHP automaticamente, assim você não precisa incluir o arquivo quando precisar da mesma. Saiba mais.
  • Objetos dinâmicos em PHP – Aula 41 – É possível criar propriedades de classe e objetos dinâmicos em PHP, ou seja, criar objetos sem criar uma classe antes, ou classes sem definir propriedades.
  • Manipulando erros em PHP – Aula 42 – Maneiras para configurar e gerenciar erros em PHP. Parte muito importante do seu código, tanto para feedback para usuário/desenvolvedor quanto para segurança.
  • Serialização e desserialização de dados PHP – Aula 43 – Serialização e desserialização de dados PHP: Salve estruturas de dados (array, objeto, etc) no BD como string e consiga recuperá-los em seu formato original
  • Como eliminar valores nulos de array em php – Aula 44 – Veja como é simples eliminar valores nulos de array em php utilizando a função array_filter. Veja também como recriar as chaves com valores numéricos.
  • Implode e Explode em PHP – Aula 45 – Aprenda a utilizar implode e explode em PHP para dividir um Array em string com algum divisor, ou criar um Array de uma string a partir de um valor divisor.
  • Namespaces em PHP – Aula 46 – Namespaces em PHP são utilizados para evitar colisões de nomes. Aprenda a utilizar este recurso e crie códigos mais robustos no seu novo projeto PHP.
  • Ler ou escrever arquivos com PHP – Aula 47 – Veja como ler ou escrever arquivos com PHP para realizar tarefas simples sem ter a necessidade de utilizar um SGBD (MySQL, PostgreSQL, ou qualquer outro).
  • Upload de imagens com PHP – Aula 48 – Veja como criar um formulário simples para upload de imagens com PHP. Suporta arquivos múltiplos e valida algumas informações sobre a imagem enviada.
  • printf e sprintf em PHP – Aula 49 – printf e sprintf em PHP são funções para exibir strings formatadas na tela, ou seja, mostram valores dependendo de diretivas para tratar tais valores. Saiba mais.
  • vprintf e vsprintf em PHP – Aula 50 – vprintf e vsprintf em PHP são funções para exibir ou criar um array formatado. Ambas as funções fazem o mesmo que printf e sprintf, porém, com arrays.
  • call_user_func e call_user_func_array em PHP – Aula 51 – call_user_func e call_user_func_array servem para executar funções dinamicamente no PHP. Muito útil quando não sabemos o nome da função a ser executada.
  • Upload de arquivos via FTP com PHP – Aula 52 – Neste artigo você vai aprender a fazer upload de arquivos via FTP com PHP utilizando as funções nativas que a linguagem nos oferece. É bastante útil, confira.
  • Como redimensionar imagens com PHP – Aula 53 – Veja como redimensionar imagens com PHP utilizando a extensão GD da linguagem. No final apresentarei uma classe para facilitar seu trabalho com imagens.
  • Exceções em PHP – Aula 54 – Exceções em PHP trouxeram uma nova maneira para manipular erros no seu código de uma maneira voltada para a programação orientada a objetos (OOP).

Até então são essas aulas que temos prontas, mas conforme descrevi, o desenvolvimento nunca para, portanto, poderão existir novidades no futuro.

Aulas extra

Abaixo algumas aulas extra para você aprimorar ainda mais no PHP:

Utilizando a estrutura MVC com PHP

  • Utilizando estrutura MVC em PHP – Parte 1 – Veja como criar uma aplicação com estrutura MVC em PHP. Vamos criar um sistema simples, com usuários, permissões e um sistema de notícias básico.
  • Utilizando estrutura MVC em PHP – Parte 2 – Para dar continuidade à nossa série de artigos sobre MVC em PHP, vamos falar sobre várias classes que geram a estrutura do nosso sistema. Veja como funciona.
  • Utilizando estrutura MVC em PHP – Parte 3 – Na parte 3 do nosso desenvolvimento de uma aplicação com estrutura MVC em PHP, vamos analisar o restante das nossas classes mais importantes do sistema.
  • Utilizando estrutura MVC em PHP – Parte 4 – Na quarta parte da série de tutoriais sobre a estrutura MVC em PHP, vamos criar a parte de cadastro de usuários, login e partes restritas no sistema.
  • Utilizando estrutura MVC em PHP – Parte 5 – Na última parte da criação da nossa aplicação com estrutura MVC em PHP, vamos criar um sistema de notícias extremamente simples, com imagem, título e texto.

Validar CPF e CNPJ com PHP

  • Classe para validar e formatar CPF e CNPJ em PHP – Classe perfeita para validar e formatar CPF e CNPJ em PHP. Fácil de utilizar e funciona perfeitamente com qualquer tipo de CPF/CNPJ, mesmo os já formatados.
  • Como validar CPF com PHP – Aprenda como fazer o cálculo para validar CPF com PHP. Também vou passar uma função pronta para reutilização em todos os seus formulários com campos de CPF.
  • Como validar CNPJ com PHP – Veja como fazer o cálculo para validar CNPJ com PHP. Também vou passar uma função pronta para reutilização em todos os seus formulários com campos de CNPJ.

Concluindo

Este é um daqueles artigos que não tem uma conclusão, ou seja, pode ser atualizado sem aviso prévio. Minha recomendação é que você salve o link em seus favoritos e sempre volte para ver se mudou algo. Além disso, acho que você tem bastante trabalho a fazer com a quantidade de material que deixei disponível para você.

Este curso é totalmente gratuito, caso queira me pagar um café, sinta-se à vontade em doar qualquer quantia que preferir no link abaixo:

Muito obrigado!

Os tipos de dados são praticamente idênticos em várias linguagens de programação, porém, você vai encontrar algumas diferenças no PHP que elevam ainda mais a facilidade de sua utilização.

Primeiramente, não é necessário declarar explicitamente que um valor é de determinado tipo. É possível criar uma variável com qualquer valor em tempo de execução do código; o interpretador do PHP vai declarar a variável e o tipo de valor que essa variável carrega.

Por exemplo:

<?php
// Declaro uma variável com tipo de dado string
$variavel = 'Um valor qualquer';

Nota: Quando estamos escrevendo códigos em PHP e sabemos que não vamos precisar incluir HTML após o código que acabamos de escrever, não é necessário utilizar a tag de fechamento do PHP ?>. Existem alguns benefícios em torno da não utilização dessa tag, veja mais detalhes.

Como você pôde ver no trecho de código acima, criei uma variável com um valor qualquer em uma única linha de código (fora o comentário); ela foi declarada com um valor do tipo string automaticamente pelo interpretador do PHP (vamos falar sobre isso no decorrer do artigo).

Os tipos de dados em PHP são úteis por vários motivos em seu script; algumas vezes para saber se é um valor numérico ou para comparar valores entre duas variáveis; noutras por questões de segurança e prevenção de SQL Injection; enfim, poderíamos ficar aqui o dia todo criando uma infinidade de cenários, porém, o importante é que você entenda que é extremamente necessário saber o que são, como criar e como verificar se determinado valor é de determinado tipo na hora da execução do seu script.

Tipos de dados em PHP

O PHP suporta oito tipos de dados primitivos e três pseudo-tipos:

Tipos básicos

  • boolean
  • integer
  • float (número de ponto flutuante, ou também double)
  • string

Tipos compostos

  • Arrays
  • Objetos

Tipos especiais

  • resource
  • NULL

Pseudo-tipos

  • mixed
  • number
  • callback

Vamos ver mais detalhes sobre cada um dos tipos abaixo.

Boolean (Booleanos)

Este é o tipo de dado mais simples que uma variável pode receber em PHP, true (verdadeiro) ou false (false).

Para criar uma variável com valor booleano, simplesmente escreva qualquer um dos dois valores da maneira que preferir, já que o interpretador do PHP não faz distinção entre letras maiúsculas e minúsculas para as palavras chave true e false.

<?php
$variavel = True; // Verdadeiro
$variavel = TRUE; // Verdadeiro
$variavel = true; // Verdadeiro
$variavel = false; // Falso
$variavel = False; // Falso
$variavel = FALSE; // Falso

Perceba que as palavras chave não devem vir entre aspas.

Além disso, qualquer valor em PHP é automaticamente convertido em true ou false quando necessário.

Uma variável será considerada falsa (false) quando ela:

  • for o próprio booleano FALSE;
  • for 0 (zero);
  • for 0.0 (zero ponto zero);
  • for um valor vazio ou “0”;
  • for um array sem elementos;
  • for um objeto sem elementos membros;
  • for NULL (incluindo variáveis não definidas);
  • for o objeto SimpleXML criado de tags vazias

Diferente disso qualquer outro valor é considerado verdadeiro (true), incluindo números negativos.

Você pode verificar se uma variável é verdadeira ou falsa simplesmente utilizando a estrutura de controle if (que você verá posteriormente neste curso).

<?php
// Cria uma variável
$variavel = 'Oi';

// Verifica se a variável é verdadeira
if ( $variavel ) {
	echo $variavel;
}

No trecho acima, a variável tem o valor Oi (verdadeiro). O comando de controle de estrutura if vai verificar se ela é verdadeira ou falsa; caso verdadeira, mostra seu valor na tela do usuário; caso falsa, não faz nada.

Integers (Inteiros)

Os integers (int) são todos os números negativos e positivos, mais o número zero (…-2, -1, 0, 1, 2…).

São os números inteiros (do conjunto Z).

Não é necessário utilizar aspas ou apóstrofos para criar uma variável com um número inteiro em PHP:

<?php
$variavel = -15542;

Números negativos devem ser representados com um sinal negativo no início; números positivos não precisam receber sinal algum (opcionalmente, você pode adicionar um sinal de mais):

$variavel = -15542; // Negativo
$variavel = 15542; // Positivo

Os números inteiros podem ser especificados em notação decimal (base 10), hexadecimal (base 16) ou octal (base 8), porém, para usar a notação octal, é necessário começar o número com um 0 (zero). Para utilizar a notação hexadecimal, inicie o número com 0x.

Exemplos:

<?php
$variavel = +1234; // número positivo
$variavel = -1234; // número negativo
$variavel =  0123; // número octal (83 em decimal)
$variavel =  0x1A; // número hexadecimal (26 em decimal)

Float (Números de ponto flutuante)

Números de ponto flutuante (também chamados de “floats”, “doubles” ou “números reais”), são números que trazem o ponto para separar a parte inteira da parte fracionária.

Em PHP, qualquer um dos exemplos abaixo é válido:

<?php
$variavel = 1.234; 
$variavel = 1.2e3; 
$variavel = 7E-10;

Strings

Uma string é uma série de caracteres misturados incluídos entre aspas ou apóstrofos.

Por exemplo:

$variavel = 'Um frase é uma string'; // String
$variavel = 'Uma palavra com um número (10) também'; // String
$variavel = 'TRUE'; // String
$variavel = 'false'; // String

Todos os exemplos acima são do tipo string.

Arrays e Objetos

Como ainda não falamos sobre arrays e objetos em nossos artigos sobre PHP, não fará muito sentido detalhar trechos de código aqui, porém, entenda que arrays são mapas  que relacionam valores com chaves. Um array pode carregar vários tipos de dados diferentes, incluindo outros arrays.

Objetos são parecidos com arrays, no entanto, eles são recursos para a programação orientada a objetos (algo que você vai entender um pouco mais adiante, se continuar seguido nossos artigos).

Resource (Recurso)

Um recurso é uma variável especial que mantém uma referência a um recurso externo (por exemplo, uma conexão MySQL, etc). Recursos são criados e usados por funções especiais que podem ser encontradas aqui.

NULL (Nulo)

Valor NULL é um valor que não tem valor nenhum (hum ?), ou, representam variáveis vazias.

Uma variável é considerada NULL se:

  • ela foi criada com a constante NULL.
$variavel = NULL;
  • ela ainda não recebeu nenhum valor.
<?php
function funcao() {
	static $variavel; // NULL
}
  • ela foi apagada com unset()
<?php
$variavel = 'Oi';
unset( $variavel ); // NULL

Pseudo-tipo mixed

O Pseudo-tipo mixed indica que um parâmetro pode aceitar vários (mas não necessariamente todos) os tipos de dados.

Pseudo-tipo number

number indica que um parâmetro pode ser tanto um integer (número inteiro) quanto float (número de ponto flutuante).

Pseudo-tipo callback

São funções que podem ser definidas por usuários e passadas como parâmetros para outras funções do PHP.

gettype: descubra o tipo

Para saber qual o tipo de uma variável, você pode utilizar a função gettype do PHP, veja:

<?php
$variavel = 'Oi';

echo gettype( $variavel ); // string

No exemplo acima, executei o comando echo do PHP, com a função gettype, na variável que havia criado. O valor retornado foi “string”.

Os possíveis valores retornados serão:

  • “boolean”
  • “integer”
  • “double” (por razões históricas “double” é retornado no caso de float, e não simplesmente “float”)
  • “string”
  • “array”
  • “object”
  • “resource”
  • “NULL”
  • “unknown type”

Modificando os tipos de dados em PHP

Em alguns casos não será possível saber qual o tipo de valor que uma variável vai retornar, no entanto, você pode forçar o interpretador do PHP para tratar o valor conforme necessário.

Por exemplo: suponhamos que eu precise de um valor inteiro em uma variável cujo valor será retornado por um campo que o usuário digitar em um input no navegador de Internet. Se este valor deve (obrigatoriamente) ser inteiro, eu posso fazer com que o PHP converta o mesmo utilizando (int) ou (integer).

Veja um exemplo:

<?php
// Uma frase número e uma frase
$variavel = '2254: Olá!';

// O valor é convertido para inteiro
echo (int)$variavel; // Exibe: 2254

Eu posso fazer isso com qualquer tipo de valor, veja as possibilidades:

  • (int), (integer) – converte para inteiro
  • (bool), (boolean) – converte para booleano
  • (float), (double), (real) – converte para número de ponto flutuante
  • (string) – converte para string
  • (binary) – converte para string binária (PHP 6)
  • (array) – converte para array
  • (object) – converte para objeto
  • (unset) – converte para NULL (PHP 5)

Exemplos:

<?php
// Uma frase número e uma frase
$variavel = '2254.54 : Olá!';

echo (int)$variavel; // Exibe: 2254
echo (bool)$variavel; // Exibe: 1 (verdadeiro)
echo (float)$variavel; // Exibe: 2254.54
echo (string)$variavel; // Exibe: 2254.54 : Olá!

print_r( (array)$variavel ); // Exibe: Array ( [0] => 2254.54 : Olá! )
var_dump( (object)$variavel ); // Exibe: object(stdClass)#1 (1) { ["scalar"]=> string(15) "2254.54 : Olá!" } 

unset($variavel); // Não exibe nada

Vídeo tutorial

O vídeo tutorial abaixo é um complemento ao texto acima:

Link do vídeo: https://www.youtube.com/watch?v=OYooJzWaGrg

Aulas anteriores

Caso queira acessar os links para aulas anteriores:

Concluindo

Em caso de dúvidas, críticas, ou qualquer outra coisa que queira falar, basta deixar um comentário aí abaixo. Estamos ansiosos para ouvir a sua opinião.

Veja todas as aulas, e mais, na categoria Curso de PHP do Tutsup.

Constantes em PHP, como o próprio nome já indica, é um objeto capaz de conter um valor fixo que nunca será alterado; uma vez definida, seu valor não poderá ser modificado até o final da execução do seu script.

Nota: Caso tente modificar o valor de uma constante, o PHP irá retornar um erro!

Semelhante às variáveis, também podemos utilizar o valor das constantes em qualquer parte do código, entretanto, devemos tomar cuidado para não utilizar os nomes das constantes pré-definidas pelo PHP. Existem várias constantes que já estão criadas e são utilizadas pela própria linguagem.

Comparação entre e Variáveis e Constantes em PHP

Vejamos abaixo uma pequena comparação entre as variáveis e as constantes em PHP:

Alteração de variáveis em PHP

Como mostrei anteriormente, utilizamos o sinal de cifrão para criar uma variável.

Por exemplo:

$valor = 100;

A variável $valor será o mesmo que 100 em qualquer parte do seu script, no entanto, eu posso falar que $variável será 200 no momento em que precisar modificar seu valor.

Veja um outro exemplo:

<?php
// Aqui o valor é 100
$variavel = 100;

// Exibe 100 na tela
echo $variavel;

// O valor agora é 200
$variavel = 200;

// Exibe 200 na tela
echo $variavel;

Perceba que a mesma variável tem dois valores diferentes no decorrer do script, um em cada parte.

Não há nenhum problema em alterar o valor de uma variável qualquer em tempo de execução; simplesmente escreva o que deseja e a mágica está feita.

Criação de constantes de PHP

Utilizamos a função define() do PHP para criar uma constante. Veja um exemplo:

define("valor", "100");

Com a função acima, definimos que, em qualquer parte do código, “valor” será “100“. Com isso, até o final da execução do meu script o valor será 100, não existe uma maneira de mudar isso.

Por exemplo, se eu tentar modificar o valor da constante:

<?php
// Cria a constante "valor"
define("valor", "100");

// Exibe a constante (100)
echo valor;

// Tento alterar o valor de uma constante
// O trecho abaixo vai gerar um erro
// Notice: Constant valor already defined in arquivo/do/erro.php on line 9
define("valor", "200");

// O valor aqui continua sendo 100
echo valor;

Perceba que, além de o valor da constante não ser alterado, seu script ainda mostrará um erro na tela.

Diferenças entre variáveis e constantes em PHP

A primeira diferença, como você viu anteriormente, é na criação. Enquanto na variável utilizamos apenas o $ (cifrão) para definir seu valor, nas constantes utilizamos uma função define().

define('NOME_DA_CONSTANTE', 'Valor da constante', false);

Nota: As constantes também são case sensitive (fazem distinção entre letras maiúsculas e minúsculas), isso significa que CONSTANTE é totalmente diferente de Constante. O último argumento da função define controla isso; se este for um valor booleano false, ou se for omitido (como fizemos nos primeiros exemplos), o interpretador do PHP vai distinguir letras maiúsculas de letras minúsculas; caso seja um valor booleano true, o PHP não vai diferenciar. Veja no exemplo abaixo:

<?php
// Cria uma constante com letras minúsculas
// O último argumento (true), diz ao interpretador do php
// para não verificar letras maiúsculas e minúsculas
define('constante', 'Valor da constante', true);

// Exibe "Valor da constante" na tela
// mesmo utilizando letras maiúsculas
// sendo que ela foi definida com letras minúsculas
echo CONSTANTE;

Outro ponto importante é na utilização; ao invés de “chamar” uma constante com o sinal de $ (cifrão) como fazemos com as variáveis, utilizamos apenas seu nome propriamente dito.

Veja uma exemplo para exibir o valor 100 no script abaixo:

// Define a variável $valor
$valor = 100;

// Define a constante valor
define("valor", "100");

// Imprime a variável
echo $valor;

// Imprime a constante
echo valor;

Como você viu no exemplo acima, existe uma pequena diferença na utilização das constantes, se as compararmos às variáveis.

Verificando se uma constante já está definida

Como descrevi anteriormente, se você tentar definir uma constante que já está definida, além do valor da constante não ser alterado, o PHP irá retornar um erro na tela explicando o que está acontecendo.

Para evitar este tipo de problema, podemos utilizar a função defined() para verificar se a constante já está definida.

<?php
// Define a constante
define( 'CONSTANTE', 'valor' );

// Verifica se a constante está definida e exibe o valor
if ( defined( 'CONSTANTE' ) ) {
	// Exibe o valor da constante
	echo CONSTANTE;
}

// Verifica se a constante NÃO está definida;
// se não, define seu valor
if ( ! defined( 'CONSTANTE' ) ) {
	// Define a constante
	define( 'CONSTANTE', 'valor' );
}

Não se preocupe com a estrutura condicional que aparece no trecho de código acima, você vai aprender a fazer isso posteriormente nessa mesma série de artigos sobre PHP.

Por agora, entenda que if verifica se uma condição é verdadeira. Se você utilizar um sinal de exclamação (!), if verifica se a condição o contrário do que você deseja:

if ( condição ) {
	ação
}

if ( ! contrário da condição ) {
	ação
}

Dicas sobre constantes em PHP

Seguem algumas dicas sobre as constantes no seu script PHP:

  • Sempre se lembre: o valor de uma constante nunca pode ser alterado na execução do script;
  • Pense bem antes de criar uma constante;
  • Considere o uso de variáveis dependendo do caso;
  • Normalmente, utilizamos todas as letras maiúsculas quando definimos uma constante (tente utilizar um padrão);
  • Cuidado com as constantes predefinidas pelo PHP.

Vídeo tutorial

O vídeo tutorial abaixo detalha o que foi descrito acima:

Link do vídeo: https://www.youtube.com/watch?v=tQ3uUWvpWe4

Aulas anteriores

Caso queira acessar o links para aulas anteriores:

Concluindo

Em caso de dúvidas, críticas, ou qualquer outra coisa que queira falar, basta deixar um comentário aí abaixo. Estamos ansiosos para ouvir a sua opinião.

Veja todas as aulas, e mais, na categoria Curso de PHP do Tutsup.

Em nossa última aula, deixei um pequeno trecho de código exibindo como funcionam as variáveis em PHP:

<?php
// Meu nome
$meu_nome = 'Luiz Otávio';

// Frase com concatenação do meu nome
$frase = 'Meu nome é ' . $meu_nome;

// Exibe a frase
echo $frase;
?>

E, conforme descrevi, hoje vamos entrar em detalhes mais profundos sobre o que são as variáveis e para qual motivo você vai utilizá-las em seu código PHP.

O que são variáveis em PHP?

As variáveis em PHP (ou em qualquer outra linguagem de programação), são objetos capazes de reter e representar valores, expressões e funções no tempo de execução do script. Cada variável está associada a uma posição de memória do seu computador ou servidor.

Por exemplo: Suponhamos que eu tenha um script onde existem milhares de linhas de código onde devo exibir meu nome (Luiz Otávio Miranda Figueiredo); para simplificar as coisas, eu poderia criar uma variável chamada lomf ($lomf) com o valor “Luiz Otávio Miranda Figueiredo”; ao invés de escrever Luiz Otávio Miranda Figueiredo todas as vezes, escreveria apenas $lomf. Com isso, o PHP vai entender que $lomf tem o valor “Luiz Otávio Miranda Figueiredo”, e todas as vezes que eu chamar essa variável, seu valor será entregue à parte do código que eu precisar.

Seria, basicamente, como apelidar partes do código.

No PHP, utilizamos o sinal de $ (Cifrão), para representar a criação ou utilização de uma variável. Na representação do nosso exemplo anterior, o código ficaria como no exemplo seguinte:

$lomf = "Luiz Otávio Miranda Figueiredo";

Uma forma simples para imprimir variáveis na tela, é utilizando o comando echo que falamos na aula anterior, assim você já pode deduzir o que o próximo exemplo faz:

echo $lomf;
// Mostra "Luiz Otávio Miranda Figueiredo" na tela do navegador

Lembre-se dos comentários

Para que você não confunda, lembre-se que tudo o que estiver depois dos caracteres // (duas barras), é contado como comentário no PHP, ou seja, não faz parte do código, mas sim observações de texto puro que escrevemos para documentação. Lembre-se que essa parte do código deve ser lida, pois, na maioria delas vou detalhar o que aquele trecho faz.

Exemplo:

// Isto é um comentário, o interpretador do PHP pula esta parte do script

Criando variáveis em PHP

Como descrevi anteriormente, criamos variáveis em PHP utilizando um sinal de cifrão ($) mais o nome que vai identificar a variável. Porém, o primeiro caractere após o cifrão deve ser uma letra ou um underline (_), nunca um número ou um traço (-).

Veja exemplos abaixo:

Correto

<?php
$_variavel               = 'Correto';
$_variavel_              = 'Correto';
$_variável_              = 'Correto';
$Variável                = 'Correto';
$variavel_qualquer       = 'Correto';
$VARIÁVEL_QUALQUER       = 'Correto';
$variavelQualquer        = 'Correto';
$variavel_22_Qualquer_11 = 'Correto';
?>

Perceba que todas as variáveis acima estão criadas de maneira correta e não vão gerar nenhum erro no programa que você estiver criando. Até existem algumas variáveis que apresentam acentos nas palavras e o PHP ainda aceita esses valores.

Observação: Sempre evite utilizar acentos nas suas variáveis, isso pode causar um problema de codificação posteriormente. Como dica, utilize apenas letras (de A a Z), underline (_) ou números (de 0 a 9).

Por fim, lembre-se que os números (de 0 a 9) só podem ser utilizados no meio ou no fim das variáveis, eles nunca devem estar após o cifrão.

Veja exemplos de variáveis criadas incorretamente, nunca faça isso:

<?php
$1variavel         = 'Incorreto';
$ variavel         = 'Incorreto';
$variavel qualquer = 'Incorreto';
$-variavel         = 'Incorreto';
$variavel-qualquer = 'Incorreto';
?>

Criando valores para variáveis em PHP

Uma variável sempre deve ter um valor qualquer, seja uma string, uma função, uma classe, enfim, qualquer coisa em PHP pode estar no valor da variável.

Para nossas aulas, vamos começar devagar e apenas utilizar strings e números.

O valor de uma variável deve vir depois de um sinal de igual (=) após a criação da mesma, ou seja:

$nome = 'João';

Perceba que os valores de strings (como vimos na aula anterior sobre o comando echo) devem estar entre aspas; já os valores numéricos não precisam delas:

<?php
$numero = 22.55;

// Exibe 22.55 na tela
echo $numero;

Concatenando (juntando) variáveis em PHP

Outro fato que você vai precisar muito em PHP é a junção (concatenação) de valores de duas ou mais variáveis.

Para fazer isso, o ponto (.) deve ser utilizado:

<?php
// Cria as variáveis com o valores necessários
$meu_nome = 'Luiz Otávio Miranda Figueiredo';
$minha_idade = 27;

// Exibe uma frase com as variáveis concatenadas
echo 'Olá, meu nome é ' . $meu_nome . ' e minha idade é ' . $minha_idade;

No exemplo anterior, existem duas variáveis com meu nome e minha idade, logo abaixo delas, utilizei o comando “echo” do PHP para exibir uma frase com o valor das variáveis.

Perceba que sempre que for necessário entrar com um comando PHP (como no caso de uma variável), eu preciso fechar as aspas, colocar um ponto, e digitar o comando. Se eu precisar entrar com outro valor que não é um comando, devo colocar outro ponto, abrir aspas, colocar o valor, e fechar as aspas. Se eu precisar fazer isso novamente, devo repetir todo o processo:

<?php
// Cria as variáveis com o valores necessários
$meu_nome = 'Luiz Otávio Miranda Figueiredo';
$minha_idade = 27;
$peso = 80;

// Exibe uma frase com as variáveis concatenadas
echo 'Nome: '   . $meu_nome    . 
     ' Idade: ' . $minha_idade .	
     ' Peso: '  . $peso;

Também perceba que o final da sua linha de código sempre deve terminar com um ponto e vírgula (;). Caso você esqueça, terá um erro na tela do navegador e o código não será executado.

Apesar de o exemplo acima ter três linhas, ele poderia ser criado apenas em uma linha e ainda sim estaria correto.

Dica: Evite fazer esse emaranhado de concatenações, mantenha seu código organizado. O mesmo trecho acima poderia ser atingido com o trecho de código abaixo:

<?php
// Cria as variáveis com o valores necessários
$meu_nome = 'Luiz Otávio Miranda Figueiredo';
$minha_idade = 27;
$peso = 80;

// Exibe uma frase com as variáveis concatenadas
echo 'Nome: '   . $meu_nome;
echo ' Idade: ' . $minha_idade;
echo ' Peso: '  . $peso;

Fica muito mais organizado.

Fazendo conta com variáveis

Como as variáveis também podem receber valores numéricos, também é possível somar, subtrair, multiplicar e dividir seu conteúdo facilmente, veja o exemplo:

$a = 1; 
// $a tem o valor 1

$b = 2; 
// $b tem o valor 2

$c = $a + $b; 
// $c tem o valor de $a(1) + $b(2) = 3

Para que você possa entender melhor, eu poderia dizer sem termos técnicos ou coisas do tipo, que uma variável seria algo parecido com um apelido de uma pessoa, assim como João da Silva Sauro tem apelido de Joãozinho na vida real, no PHP podemos dar um apelido para qualquer coisa utilizando variáveis, como em nosso exemplo anterior, onde $a representou 1, $b o número 2 e $c a soma das duas variáveis ($a + $b), que resultou no número 3.

O mesmo se aplica para subtrair, multiplicar e dividir, veja o exemplo:

$a = 10; 
// $a tem o valor 10
$b = 2; 
// $b tem o valor 2
$c = $a - $b; 
// $c tem o valor de $a(10) menos o valor de $b(2) = 8
$c = $a / $b; 
// $c tem o valor de $a(10) dividido pelo valor de $b(2) = 5
$c = $a * $b;
// $c tem o valor de $a(10) multiplicado pelo valor de $b(2) = 20

Cuidado com as variáveis

No PHP temos algumas variáveis que são predefinidas para utilização, com isso, não podemos utilizar estas variáveis com outro valor, veja um exemplo incorreto da utilização de variáveis predefinidas:

$GLOBALS = "Qualquer valor"; 
// $GLOBALS faz referencia para todas variáveis disponíveis no escopo global

$_SERVER = "Qualquer valor"; 
// $_SERVER contém Informação do servidor e ambiente de execução do script

$_GET = "Qualquer valor"; 
// $_GET contém informações do HTTP GET

$_POST = "Qualquer valor"; 
// $_POST contém informações do HTTP POST

$_FILES = "Qualquer valor"; 
// $_FILES contém dados de arquivos enviados HTTP File Upload

$_REQUEST = "Qualquer valor"; 
// $_REQUEST contém informações das Variáveis de requisição HTTP

$_SESSION = "Qualquer valor"; 
// $_SESSION contém dados das variáveis de sessão

$_ENV = "Qualquer valor"; 
// $_ENV contém valores das variáveis de ambiente

$_COOKIE = "Qualquer valor"; 
// $_COOKIE contém valores dos Cookies HTTP

$php_errormsg = "Qualquer valor"; 
// $php_errormsg contém valores de erros do PHP

$HTTP_RAW_POST_DATA = "Qualquer valor";
// $HTTP_RAW_POST_DATA contém Informação não-tratada do POST

$http_response_header = "Qualquer valor"; 
// $http_response_header contém valores dos cabeçalhos de resposta HTTP

$argc = "Qualquer valor"; 
// $argc contém o número de argumentos passados para o script

$argv = "Qualquer valor"; 
// $argv contém o array de argumentos passados para o script

Todos os exemplos acima estão incorretos e não devem ser utilizados na execução do seu script.

Outro ponto importante que você deve lembrar, é que também não podemos utilizar caracteres especiais (Espaço, -, *, &, |, (), ¨,%, etc) no meio da variável.

Veja outro exemplo de variáveis incorretas:

$Tuts up = "Blog";
// Está incorreto, não podemos utilizar o espaço
// O correto seria:
$Tuts_up = "Blog";

Por fim, devemos saber que o PHP é uma linguagem Case sensitive, ou seja, faz distinção entre letras maiúsculas e minúsculas, logo você já pode deduzir que $Tutsup é diferente de $tutsup, as duas variáveis podem receber valores diferentes no mesmo script.

Por exemplo:

<?php
// Cria as variáveis com o valores necessários
$tutsup = 'blog';
$Tutsup = 'Tutsup';

// Tenho um blog chamado Tutsup
echo 'Tenho um ' . $tutsup . ' chamado ' . $Tutsup;

Aspas duplas e variáveis em PHP

Um ponto interessante das aspas duplas em PHP, é que seu interpretador vai ler o código que estiver dentro delas, por exemplo:

<?php
$meu_nome = 'Luiz Otávio';

// Aspas simples exibe: Meu nome é $meu_nome
echo 'Meu nome é $meu_nome';

// Aspas duplas interpreta o código: Meu nome é Luiz Otávio
echo "Meu nome é $meu_nome";

Perceba que na primeira parte do código utilizei aspas simples, com isso o interpretador do PHP não conseguiu interpretar a variável $meu_nome; então isso foi exibido na tela:

Meu nome é $meu_nome

Na segunda parte do código utilizei aspas duplas, assim o interpretador do PHP conseguiu ler variável $meu_nome:

Meu nome é Luiz Otávio

Talvez seja melhor utilizar aspas duplas do que concatenar variáveis com o ponto, vai depender de você.

Veja um exemplo que mostrei anteriormente neste artigo, porém, agora vou utilizar aspas duplas e não o ponto:

<?php
// Cria as variáveis com o valores necessários
$meu_nome = 'Luiz Otávio Miranda Figueiredo';
$minha_idade = 27;
$peso = 80;

// Exibe: Nome: Luiz Otávio Miranda Figueiredo Idade: 27 Peso: 80
echo "Nome: $meu_nome Idade: $minha_idade Peso: $peso";

Bem mais simples, não?

Escopo das variáveis em PHP

Apesar de ser uma área que ainda vamos chegar neste curso, é importante que você saiba que variáveis pode ter escopo local ou global.

Uma variável global estará disponível em todo o seu script; uma variável local estará disponível somente dentro da função que a criou.

Veja o exemplo abaixo (não se preocupe, você vai aprender isso posteriormente):

<?php
// Cria uma variável comum
$variavel_global = 10;

function soma() {
	// Define que $variavel_global é global
	global $variavel_global;
	
	// Cria uma variável local (apenas dentro da função)
	$variavel_local = 20;
	
	// Soma o valor das duas variáveis
	return $variavel_global + $variavel_local;
}

// Exibe 10 na tela;
echo $variavel_global;

// Exibe um erro na tela dizendo que a variável não está definida
echo $variavel_local;

// Exibe 30 na tela
echo soma();

No exemplo acima, temos uma variável global (que poderá ser acessada fora e dentro da função) e uma variável local, que, se for acessada fora da função, é tratada como variável indefinida.

Variáveis geradas dinamicamente

Outro ponto interessante que você vai ter que utilizar qualquer dia desses, são as variáveis criadas dinamicamente. Apesar de ser um pouco confuso, é importante que você entenda este conceito.

As variáveis criadas dinamicamente são geradas através do valor de outra variável qualquer, por exemplo:

<?php
// Cria uma variável com um valor qualquer
$variavel = 'valor';

// Utilizar o valor da variável para criar uma nova variável com valor
// dinâmico
$$variavel = 'dinâmico';

// Exibe: dinâmico
echo $valor;

Perceba que eu não criei uma variável chamada $valor, ela foi gerada dinamicamente através de dois sinais de cifrão $$ (ao invés de um).

Funciona basicamente assim: tenho uma variável $X com valor V, se eu utilizar $$X, vou utilizar V (valor de $X) para criar uma nova variável $V, veja isso na prática novamente:

<?php
$X = 'V';
$$X = 'Sou o valor de $V';

// Exibe: Sou o valor de $V
echo $V;

Entenda isso, pois, em alguns casos só este método vai resolver seu problema.

Vídeo tutorial

O vídeo abaixo complementa o texto acima:

Link do vídeo: https://www.youtube.com/watch?v=0NEl8d_lRZc

Aulas anteriores

Caso queira acessar o links para aulas anteriores:

Concluindo

Em caso de dúvidas, críticas ou qualquer outra coisa que queira falar, basta deixar um comentário aí abaixo. Estamos ansiosos para ouvir a sua opinião.

Veja todas as aulas, e mais, na categoria Curso de PHP do Tutsup.

Agora que já criamos nosso servidor, estipulamos um editor de textos padrão e criamos nosso primeiro script em PHP, temos que entender como funciona a linguagem. Vamos começar pelas aspas e o comando echo, que tratam de uma das partes mais utilizadas em todos os scripts em PHP, a exibição de conteúdo na tela do navegador.

Observação: Antes de continuar a leitura, crie uma pasta dentro da nossa pasta “php” (que está dentro da pasta “cursos”) chamada “aula_2”. Dentro dessa última, crie um arquivo chamado “index.php” e teste todos os scripts que criaremos nessa aula nesse arquivo. (Vimos sobre isso na primeira aula).

Echo em PHP

Como vimos em nossa primeira aula, tudo o que é parte do código PHP deve estar entre as tags de abertura da linguagem <?php e ?>. Por exemplo, se eu abrir o arquivo index.php e digitar o seguinte:

<?php
echo 1;
?>

E abrir o endereço http://127.0.0.1/cursos/php/aula_2/ em meu navegador, verei exatamente o número 1 na tela.

Isso acontece porque o comando echo serve simplesmente para exibir algo na tela quando seu programa for executado, porém, você deve tomar alguns cuidados antes de utilizar este comando.

Como você pode utilizar o comando echo para exibir strings, é necessário que você utilize aspas simples ou duplas para que os valores que você deseja exibir, não sejam interpretados como linhas de código pelo interpretador do PHP. Nesse caso, sempre que for necessário exibir um texto comum, você deve envolver o conteúdo do texto entre aspas simples ou duplas.

Veja um exemplo:

<?php
echo 'Posso exibir quase qualquer coisa aqui dentro.';
?>

Veja o que acontece no trecho acima:

  • <?php – A tag de abertura do PHP;
  • echo – Um dos comandos mais utilizados em PHP, exibe algo na tela;
  • Aspas simples (‘) – Indica que estou abrindo um container onde posso escrever praticamente qualquer coisa;
  • Texto: Posso exibir quase qualquer coisa aqui dentro.
  • Aspas simples (‘) – Indica que estou fechando o container que havia aberto anteriormente;
  • Ponto e vírgula (;) – Sempre que você terminar de escrever um código em PHP, deve fechar o trecho com um ponto e vírgula;
  • ?> – Tag de fechamento do código PHP.

Se eu executar o trecho acima em meu navegador, o texto “Posso exibir quase qualquer coisa aqui dentro.” será mostrado na tela.

Se eu quiser exibir vários textos em sequência, posso fazer da seguinte maneira:

<?php
echo 'Texto 1 ';
echo 'Texto 2 ';
echo 'Texto 3 ';
echo 'Texto 4 ';
echo 'Texto 5 ';
?>

Se você executar o trecho acima em seu navegador, verá todos os textos que estão entre as aspas, porém, em uma única linha. Isso acontece porque nada que está fora das aspas é considerado pelo comando echo, assim, não existem quebras de linhas, apenas os próprios espaços que estão dentro das aspas.

Se você quisesse que os espaços aparecessem, poderia fazer da seguinte maneira:

<?php
echo 'Texto 1
Texto 2 
Texto 3 
Texto 4 
Texto 5';
?>

Perceba que antes de fechar as aspas e utilizar o ponto e vírgula para finalizar minha linha de código, eu pulei as linhas dentro do comando echo, assim obtive o seguinte resultado:

Texto 1
Texto 2 
Texto 3 
Texto 4 
Texto 5

No entanto, você só vai conseguir visualizar as quebras de linha se exibir o código fonte do seu navegador (CTRL + U), isso acontece porque seu navegador está renderizando HTML e não texto puro (como estamos exibindo). Se quiséssemos que o navegador mostrasse um texto em cada linha, deveríamos escrever uma tag de quebra de linha ao final de cada linha. Por exemplo:

<?php
echo 'Texto 1 <br />
Texto 2  <br />
Texto 3  <br />
Texto 4  <br />
Texto 5';
?>

Ou:

<?php
echo 'Texto 1 <br />';
echo 'Texto 2 <br />';
echo 'Texto 3 <br />';
echo 'Texto 4 <br />';
echo 'Texto 5 ';
?>

A tag <br /> fará o serviço de pular uma linha cada vez que o navegador a encontrar, portanto, teremos o seguinte:

Exemplo do comando echo em PHP

E se analisarmos o código-fonte do navegador, veremos o seguinte:

Exemplo do código-fonte do navegador

Exatamente o que queríamos.

Exibindo HTML dentro do comando echo

Se você precisar exibir HTML dentro do comando echo, na verdade não precisa fazer nada além de escrever o que precisa. Veja um exemplo:

<?php
echo '<h1>Este é meu cabeçalho em HTML</h1>';
echo '<p>Este é meu parágrafo <b>com isso em negrito</b></p>';
?>

Isso vai gerar exatamente o HTML que você enviou dentro do comando echo, ou seja:

HTML gerado com echo em PHP

Porém, pode acontecer ao contrário e você precisar exibir HTML fora do contexto do PHP. Para esses casos é mais simples ainda, basta fechar abrir e fechar as tags de abertura do PHP sempre que precisar escrever algum trecho em PHP.

Vamos ver no código como ficaria:

<!doctype html>
<html>
	<head>
		<meta charset="UTF-8">
		
		<title><?php echo 'título';?></title>
	</head>
	<body>
		<h1>Cabeçalho</h1>
		<?php echo '<p>Qualquer coisa em PHP</p>';?>
	</body>
</html>

Perceba no trecho acima, que estou intercalando PHP e HTML, com isso, posso abrir e fechar as tags do PHP quantas vezes forem necessárias.

Aspas e echo em PHP

Conforme descrevi anteriormente, você deve utilizar aspas simples ou duplas sempre que for necessário escrever algo que o PHP não entende como código, como um texto simples (também chamado de string). Porém, e se esse texto também tiver aspas simples ou duplas?

Veja o que acontece:

<?php
echo 'Meu texto tem 'aspas'';
?>

No trecho acima, as aspas que estão dentro do texto estão fazendo o código se comportar de maneira incorreta, isso porque a primeira aspa simples do texto, está, na verdade, fechando a aspas simples do código.

Isso irá gerar um erro de sintaxe:

Parse error: syntax error, unexpected ‘aspas’ (T_STRING), expecting ‘,’ or ‘;’ in E:ProgramasEasyPHPdatalocalwebcursosphpaula_2index.php on line 2

Para resolver este problema, existem duas maneira:

  • Intercalar aspas duplas e aspas simples;
  • Utilizar a barra invertida () para escapar as aspas que não forem do código

Na primeira opção, podemos abrir o nosso código aspas duplas ao invés de aspas simples, assim, as aspas do texto não afetarão as aspas do código:

<?php
echo "Meu texto tem 'aspas'";
?>

O mesmo acontece quando utilizamos aspas duplas dentro do texto, basta alterar as aspas do código para aspas simples:

<?php
echo 'Meu texto tem "aspas"';
?>

Porém, pode chegar um dia em que não existe outra possibilidade, é necessário colocar as mesmas aspas do código dentro do texto (ou vice-versa). Nesse caso, você pode utilizar a barra invertida () como caractere de escape antes de cada uma das aspas do texto.

<?php
echo 'Meu texto tem 'aspas'';
?>

As barras invertidas não aparecem na saída do comando echo, simplesmente servem para escapar as aspas simples ou duplas que forem utilizadas na sua string dentro do código.

Considerações finais sobre as aspas

Apesar do texto acima estar bem detalhado, vale ressaltar alguns pontos interessantes sobre as aspas:

  • Não é permitido abrir com aspas simples e fechar com aspas duplas (ou vice-versa):
<?php
echo 'Meu texto'; // Correto ''
echo "Meu texto"; // Correto ""
echo 'Meu texto"; // Incorreto '"
echo "Meu texto'; // Incorreto "'
?>
  • Utilize aspas intercaladas quando seu texto tiver aspas:
<?php
echo 'Meu texto com "aspas"'; // Correto
echo "Meu texto com 'aspas'"; // Correto
echo 'Meu texto com 'aspas''; // Incorreto
echo "Meu texto com "aspas""; // Incorreto
?>
  • Utilize a barra invertida () para escapar aspas se for necessário utilizar as mesmas aspas no texto e no código;
echo 'Meu texto com "aspas"'; // Correto
echo "Meu texto com 'aspas'"; // Correto
echo 'Meu texto com 'aspas''; // Correto
echo "Meu texto com "aspas""; // Correto

Comentários em PHP

Normalmente quando escrevemos códigos em PHP, o arquivo ficará gigante, com várias linhas e trecho que fazem coisas diferentes. Por este motivo, vai chegar um momento em que não vamos mais entender o que fizemos naquele código, como corrigimos determinado problema, ou porque existe uma linha a mais para fazer determinada tarefa.

Para resolver este problema, precisamos documentar o que estamos fazendo, simplesmente escrever o que determinada linha ou função faz para que possamos lembrar depois.

Em PHP, utilizamos os comentários para documentar nossos códigos, isso garante que sempre que alguém ler aquele código, saberá exatamente como manipulá-lo, até mesmo você, quando esquecer porque escreveu aquela função estranha (e vai por mim, a gente esquece mesmo).

Existem várias maneiras de comentar em PHP, mas vejamos apenas duas: utilizando duas barra (//) ou os caracteres /* e */.

Os comentários com duas barras (//) servem apenas para uma linha:

<?php
// Isso é um comentário
echo 'Isso é código';

// Isso é outro comentário
echo 'Isso é código';
?>

O interpretador do PHP ignora os comentários, assim, eles não atrapalham seu código, não geram erros e não aparecem na saída final.

Os comentários com os sinais de /* e */, equivalem para comentários com quantas linhas você desejar, porém, você sempre deve fechar os comentários com */. Veja um exemplo:

<?php
/* Isso é um comentário 
e eu posso utilizar quantas
linhas eu precisar,
contando que feche os comentários 
com --> */
echo 'Isso é código';
?>

Considerações finais sobre echo em PHP

Como eu descrevi ao longo do artigo, o comando echo é um dos comandos mais utilizados em PHP, e você pode exibir praticamente tudo o que quiser.

Basicamente, você vai utilizar este comando para exibir variáveis, que são uma forma para guardar valores em PHP, veja um exemplo:

<?php
// Meu nome
$meu_nome = 'Luiz Otávio';

// Frase com concatenação do meu nome
$frase = 'Meu nome é ' . $meu_nome;

// Exibe a frase
echo $frase;
?>

Ainda vamos ver variáveis em muito mais detalhes, porém, saiba que elas são uma forma de salvar um valor qualquer em um trecho de texto bem menor. Em PHP utilizamos o sinal de $ (cifrão) para criar uma variável (conforme o código acima mostra). Caso queira concatenar (juntar duas variáveis), basta utilizar um ponto (.).

Não entre em pânico sobre variáveis ainda, vamos falar sobre isso na próxima aula. Por agora, brinque com os trechos de código que deixei no artigo para pegar intimidade com a linguagem.

Na próxima aula aprofundaremos muito mais.

Vídeo tutorial

O vídeo tutorial abaixo é um complemento ao texto acima:

Link do vídeo: https://www.youtube.com/watch?v=jCUlliIPjvg

Aula anterior

Caso queira acessar a aula anterior, segue o link:

Concluindo

Em caso de dúvidas, críticas ou qualquer outra coisa que queira falar, basta deixar um comentário aí abaixo. Estamos ansiosos para ouvir a sua opinião.

Veja todas as aulas, e mais, na categoria Curso de PHP do Tutsup.

Lançar (throw) e capturar (try / catch) exceções em PHP é parte essencial da sua programação orientada a objetos. Com elas você pode criar um “erro” (uma exceção) que deverá ser capturado quando a classe ou função for executada.

Utilizamos throw para lançar uma nova exceção da seguinte maneira:

<?php
function mensagem ( $mensagem = null ) {
    // Verifica se a mensagem NÃO foi enviada
    if ( ! $mensagem ) {
        // Lança uma nova exceção
        throw new Exception('Mensagem não enviada!');
    }
    
    // Exibe a mensagem
    echo $mensagem;
}
?>

No código acima, criei uma função que exibirá uma mensagem que deverá (obrigatoriamente) ser enviada para o parâmetro $mensagem da mesma. Se a mensagem não for enviada pelo desenvolvedor, lanço uma exceção detalhando o que ocorreu.

Quando throw é encontrado pelo interpretador do PHP, o código irá ler o que ele diz e não executará o restante daquela função, ou seja, eu não preciso verificar novamente se o parâmetro foi enviado para continuar escrevendo o restante dos códigos daquela função.

Um ponto importante a ser ressaltado, é que agora você não deve executar a função diretamente, como era de costume.

// Executa a função sem o parâmetro mensagem
mensagem();

Isso irá lançar o seguinte erro fatal:

Fatal error: Uncaught exception ‘Exception’ with message ‘Mensagem não enviada!’ in D:hd_antigoProgramasEasyPHPdatalocalwebindex.php:6 Stack trace: #0 D:hd_antigoProgramasEasyPHPdatalocalwebindex.php(14): mensagem() #1 {main} thrown in D:hd_antigoProgramasEasyPHPdatalocalwebindex.php on line 6

O que aconteceu no erro acima foi que o interpretador do PHP encontrou uma exceção lançada com o bloco throw na linha 6 do arquivo index.php, mas não encontrou uma maneira de capturar essa exceção.

Capturar uma exceção significa utilizar o bloco try para tentar executar a função, e pelo menos um bloco catch para capturar e manipular o erro.

A maneira mais simples para resolver o problema acima seria:

// Executa o código
try {
    // Executa a função sem o parâmetro mensagem
    mensagem();
} catch( Exception $e ) {
    // Exibe a exceção (erro)
    echo $e->getMessage();
}

O bloco try/catch em PHP funcionam de maneira similar às estruturas condicionais em PHP, porém, ao invés de imaginar “Se / se não”, imagine “Tente / capture”.

Try sempre será executado enquanto um throw não for encontrado. Se throw for encontrado pelo interpretador do PHP, o código daquela função ou método imediatamente para de ser executado e os comandos do bloco catch serão executados.

Veja mais um exemplo, mas agora com classes PHP:

<?php
// Cria uma classe
class Mensagem
{
    // Um método
    public function exibe( $mensagem = false ) {
        // Verifica se a mensagem NÃO (!) foi enviada como parâmetro
        if ( ! $mensagem ) {
            throw new Exception('Envie a mensagem em $mensagem!');
        }
        
        // Exibe a mensagem
        echo $mensagem;
    }
}

// Executa o código
try {
    // Cria uma instância da classe
    $mensagem = new Mensagem();
    
    // Executa o método exibe
    $mensagem->exibe();
} catch( Exception $e ) {
    // Exibe a exceção (erro)
    echo $e->getMessage();
}
?>

No código acima, o bloco catch será executado, já que tentamos executar o método “exibe” sem enviar o parâmetro $mensagem. Consequentemente, ao invés de exibir qualquer coisa na tela, o usuário verá apenas:

Envie a mensagem em $mensagem!

Para que o bloco try seja executado, deveríamos executar o método “exibe” da seguinte maneira:

$mensagem->exibe("Oi, agora tenho uma mensagem!");

E resolveríamos o problema do parâmetro $mensagem.

Você também pode estender a classe “Exception” para criar suas próprias exceções da seguinte maneira:

<?php
// Nova exceção
class MinhaExcecao Extends Exception { }

Nesse caso nosso código mudaria um pouco, veja:

<?php
// Nova exceção
class MinhaExcecao Extends Exception { }

// Cria uma classe
class Mensagem
{
    // Um método
    public function exibe( $mensagem = false ) {
        // Verifica se a mensagem NÃO (!) foi enviada como parâmetro
        if ( ! $mensagem ) {
            // Lança a nova excessão
            throw new MinhaExcecao('Envie a mensagem em $mensagem!');
        }
        
        // Exibe a mensagem
        echo $mensagem;
    }
}

// Executa o código
try {
    // Cria uma instância da classe
    $mensagem = new Mensagem();
    
    // Executa o método exibe
    $mensagem->exibe();
} catch( MinhaExcecao $e ) {
    // Exibe a exceção (erro)
    echo $e->getMessage();
}
?>

No trecho de código acima, ao invés de lançar e capturar exceções na classe “Exception”, faço o mesmo na minha nova classe de exceções “MinhaExcecao”.

Uma parte importante da classe “Exception” no PHP, é que ela tem vários métodos interessantes, são eles:

  • getMessage () – A mensagem de erro
  • getCode () – O código de erro
  • getFile () – O arquivo de erro
  • getLine () – A linha do erro
  • getTrace () – Informações de contexto do erro
  • getTraceAsString () – Mesmo informação anterior, só que com string

Com isso podemos gerar erros mais precisos, veja:

// Executa o código
try {
    // Cria uma instância da classe
    $mensagem = new Mensagem();
    
    // Executa o método exibe
    $mensagem->exibe();
} catch( MinhaExcecao $e ) {
    echo '<b>Erro: </b>';
    echo $e->getMessage() . '<br>';
    echo ' <b>Na linha: </b>';
    echo $e->getLine() . '<br>';
    echo ' <b>Arquivo: </b>';
    echo $e->getFile() . '<br>';
}

O trecho de código acima deverá lançar um erro da seguinte maneira:

Erro: Envie a mensagem em $mensagem!
Na linha: 13
Arquivo: D:hd_antigoProgramasEasyPHPdatalocalwebindex.php

Bem mais detalhado.

Concluindo

Exceções trazem uma nova maneira de trabalhar com o PHP Orientado a Objetos, deixando o PHP mais próximo de linguagens como Java ou C. Utilize com sabedoria.

Caso queira tirar alguma dúvida, basta deixar um comentário.

Na maioria dos sistemas que criamos temos que utilizar imagens. Seja para um perfil de usuário, envio de um logo, galerias e assim por diante.

O PHP não só no oferece a possibilidade de criar página inteiramente dinâmicas, mas também de criar imagens dinamicamente. Com a extensão GD, de fato, você pode até mesmo criar imagens do zero, fazer desenhos, colorir e fazer mais algumas coisas legais.

Neste artigo você vai aprender a redimensionar imagens em PHP de duas maneiras; ou deixar a imagem em um local temporário e destruindo-a assim que ela for exibida, ou salvar a mesma em uma pasta permanente do seu servidor.

Ao final do artigo, vou mostrar uma classe que criei para redimensionar imagens em JPG, PNG e GIF. Assim você não vai precisar passar por todo o processo toda vez que precisar do redimensionamento.

Nota: Normalmente a biblioteca GD já vem com a instalação do PHP acima de versões 4.3, mas se no seu caso precisar fazer a instalação, siga os passos do Manual do PHP – Instalação da extensão GD.

Se você estiver utilizando o Windows, basta remover o comentário da seguinte linha:

extension=php_gd2.dll

Veja:

extension=php_gd2.dll

extension=php_gd2.dll

Então vamos lá.

Como redimensionar imagens com PHP

O primeiro passo para redimensionar uma imagem é verificar qual tipo de imagem você está manipulando. Neste tutorial vamos passar por três dos formatos mais utilizados na Web: PNG, GIF e JPG.

Vamos começar com JPG.

Imagens JPG com PHP

1 – Crie uma pasta qualquer aí no seu servidor e copia uma imagem JPG para essa pasta. Para nosso exemplo vou nomear meu arquivo de teste.jpg.

2 – Crie um arquivo PHP chamado index.php e vamos trabalhar dentro dele.

3 – Para iniciar, temos que criar uma imagem jpg a partir do arquivo que temos em nosso servidor (pode ser uma URL também). Para isso, utilize a função imagecreatefromjpeg, veja:

// O caminho da nossa imagem no servidor
$caminho_imagem = 'teste.jpg';

// Retorna o identificador da imagem
$imagem = imagecreatefromjpeg($caminho_imagem);

4 – Agora vamos capturar a largura e altura da nossa imagem. Para isso utilize a função getimagesize. Essa função nos retorna um array com os valores da imagem, sendo a primeira chave a largura, e segunda a altura (além de outras coisas). Com isso, podemos utilizar a função list para gerar variáveis na ordem largura/altura. Veja:

// Cria duas variáveis com a largura e altura da imagem
list( $largura, $altura ) = getimagesize( $caminho_imagem );

5 – Agora vamos utilizar uma proporção para redimensionar as imagens. Você pode utilizar o que preferir, até mesmo um tamanho fixo para largura e altura. Vou utilizar este método para simplificar o nosso tutorial. Nossa nova imagem terá 50% do tamanho original da imagem que estamos redimensionando.

// Nova largura e altura
$proporcao = 0.5;
$nova_largura = $largura * $proporcao;
$nova_altura = $altura * $proporcao;

Ou seja, a nova altura é a largura original vezes nossa proporção. O mesmo para altura.

6 – Agora vamos criar uma nova imagem em branco com as novas dimensões. Para isso utilizamos a função imagecreatetruecolor.

// Cria uma nova imagem em branco
$nova_imagem = imagecreatetruecolor( $nova_largura, $nova_altura );

Agora temos um identificador da nossa nova imagem.

7 – Temos que copiar a imagem original para a nova imagem com o novo tamanho, para isso utilizamos a função imagecopyresampled.

// Copia a imagem para a nova imagem com o novo tamanho
imagecopyresampled(
    $nova_imagem, // Nova imagem 
    $imagem, // Imagem original
    0, // Coordenada X da nova imagem
    0, // Coordenada Y da nova imagem 
    0, // Coordenada X da imagem 
    0, // Coordenada Y da imagem  
    $nova_largura, // Nova largura
    $nova_altura, // Nova altura
    $largura, // Largura original
    $altura // Altura original
);

Essa função faz praticamente tudo, até mesmo corta a imagem se você precisar. Para nosso caso, estamos apenas redimensionando a imagem (Veja os comentários acima para entender melhor).

8 – Agora temos que gerar uma imagem JPG (o mesmo formato da imagem original). Para isso utilizamos a função imagejpeg do PHP.

// Cria a imagem
imagejpeg( $nova_imagem, 'nova_imagem.jpg', 100 );

O trecho acima irá salvar a nova imagem em um arquivo chamado nova_imagem.jpg com 100 de qualidade. Se você quisesse apenas exibir uma imagem temporária, bastaria configurar o segundo parâmetro da função como NULL, porém, você deveria adicionar um cabeçalho indicando que o conteúdo da página é uma imagem. Veja como ficaria:

// Cabeçalho
header('Content-type: image/jpg');

// Cria a imagem
imagejpeg( $nova_imagem, null, 100 );

Agora a imagem não é mais salva no disco, apenas exibida na tela.

9 – Por fim, temos que destruir as imagens que criamos. Fazemos isso da seguinte maneira:

// Remove as imagens temporárias
imagedestroy($imagem);
imagedestroy($nova_imagem);

E pronto! Agora temos nossa nova imagem redimensionada.

Código completo para redimensionar imagem JPG

Veja como ficou o código completo:

<?php
// O caminho da nossa imagem no servidor
$caminho_imagem = 'teste.jpg';

// Retorna o identificador da imagem
$imagem = imagecreatefromjpeg($caminho_imagem);

// Cria duas variáveis com a largura e altura da imagem
list( $largura, $altura ) = getimagesize( $caminho_imagem );

// Nova largura e altura
$proporcao = 0.5;
$nova_largura = $largura * $proporcao;
$nova_altura = $altura * $proporcao;

// Cria uma nova imagem em branco
$nova_imagem = imagecreatetruecolor( $nova_largura, $nova_altura );

// Copia a imagem para a nova imagem com o novo tamanho
imagecopyresampled(
    $nova_imagem, // Nova imagem 
    $imagem, // Imagem original
    0, // Coordenada X da nova imagem
    0, // Coordenada Y da nova imagem 
    0, // Coordenada X da imagem 
    0, // Coordenada Y da imagem  
    $nova_largura, // Nova largura
    $nova_altura, // Nova altura
    $largura, // Largura original
    $altura // Altura original
);

// Cria a imagem
imagejpeg( $nova_imagem, 'nova_imagem.jpg', 100 );

// Remove as imagens temporárias
imagedestroy($imagem);
imagedestroy($nova_imagem);
?>

Para os outros formatos, mudamos apenas algumas linhas de código. Vamos ver como funcionam PNG e GIF posteriormente.

Redimensionando imagens PNG com PHP

O processo é praticamente o mesmo, apenas mudamos duas funções. Ao invés de imagecreatefromjpeg, usaremos imagecreatefrompng e ao invés de  imagejpeg usaremos imagepng.

Observação: A qualidade para PNG deve ir de 0 a 9, não de 0 a 100.

Veja o código completo:

<?php
// O caminho da nossa imagem no servidor
$caminho_imagem = 'teste.png';

// Retorna o identificador da imagem
$imagem = imagecreatefrompng($caminho_imagem);

// Cria duas variáveis com a largura e altura da imagem
list( $largura, $altura ) = getimagesize( $caminho_imagem );

// Nova largura e altura
$proporcao = 0.5;
$nova_largura = $largura * $proporcao;
$nova_altura = $altura * $proporcao;

// Cria uma nova imagem em branco
$nova_imagem = imagecreatetruecolor( $nova_largura, $nova_altura );

// Copia a imagem para a nova imagem com o novo tamanho
imagecopyresampled(
    $nova_imagem, // Nova imagem 
    $imagem, // Imagem original
    0, // Coordenada X da nova imagem
    0, // Coordenada Y da nova imagem 
    0, // Coordenada X da imagem 
    0, // Coordenada Y da imagem  
    $nova_largura, // Nova largura
    $nova_altura, // Nova altura
    $largura, // Largura original
    $altura // Altura original
);

// Cria a imagem
imagepng( $nova_imagem, 'nova_imagem.png', 1 );

// Remove as imagens temporárias
imagedestroy($imagem);
imagedestroy($nova_imagem);
?>

Pronto! Temos uma imagem PNG redimensionada.

Lembre-se de ler a primeira parte deste tutorial (falando sobre JPG), nela eu detalho todas as etapas do processo.

Redimensionando imagens GIF com PHP

O processo é o mesmo, apenas mudamos duas funções. Ao invés de imagecreatefromjpeg, usaremos imagecreatefromgif e ao invés de  imagejpeg usaremos imagegif.

Observação: GIF não tem o parâmetro qualidade. Outro fato interessante para você saber, é que para GIFs você só terá a primeira imagem, não todas as imagens de uma ação.

Veja o código completo:

<?php
// O caminho da nossa imagem no servidor
$caminho_imagem = 'teste.gif';

// Retorna o identificador da imagem
$imagem = imagecreatefromgif($caminho_imagem);

// Cria duas variáveis com a largura e altura da imagem
list( $largura, $altura ) = getimagesize( $caminho_imagem );

// Nova largura e altura
$proporcao = 0.5;
$nova_largura = $largura * $proporcao;
$nova_altura = $altura * $proporcao;

// Cria uma nova imagem em branco
$nova_imagem = imagecreatetruecolor( $nova_largura, $nova_altura );

// Copia a imagem para a nova imagem com o novo tamanho
imagecopyresampled(
    $nova_imagem, // Nova imagem 
    $imagem, // Imagem original
    0, // Coordenada X da nova imagem
    0, // Coordenada Y da nova imagem 
    0, // Coordenada X da imagem 
    0, // Coordenada Y da imagem  
    $nova_largura, // Nova largura
    $nova_altura, // Nova altura
    $largura, // Largura original
    $altura // Altura original
);

// Cria a imagem
imagegif( $nova_imagem, 'nova_imagem.gif' );

// Remove as imagens temporárias
imagedestroy($imagem);
imagedestroy($nova_imagem);
?>

Pronto, agora temos uma nova imagem GIF redimensionada.

Considerações sobre sobrescrever as imagens

Se você quiser sobrescrever a imagem original para não ficar guardando várias imagens dentro do servidor, basta colocar o mesmo nome da imagem original na última função (que salva a imagem), são elas: imagejpeg, imagepng e imagegif.

Veja nosso último exemplo (gif), porém agora sobrescrevendo a imagem original:

<?php
// O caminho da nossa imagem no servidor
$caminho_imagem = 'teste.gif';

// Retorna o identificador da imagem
$imagem = imagecreatefromgif($caminho_imagem);

// Cria duas variáveis com a largura e altura da imagem
list( $largura, $altura ) = getimagesize( $caminho_imagem );

// Nova largura e altura
$proporcao = 0.5;
$nova_largura = $largura * $proporcao;
$nova_altura = $altura * $proporcao;

// Cria uma nova imagem em branco
$nova_imagem = imagecreatetruecolor( $nova_largura, $nova_altura );

// Copia a imagem para a nova imagem com o novo tamanho
imagecopyresampled(
    $nova_imagem, // Nova imagem 
    $imagem, // Imagem original
    0, // Coordenada X da nova imagem
    0, // Coordenada Y da nova imagem 
    0, // Coordenada X da imagem 
    0, // Coordenada Y da imagem  
    $nova_largura, // Nova largura
    $nova_altura, // Nova altura
    $largura, // Largura original
    $altura // Altura original
);

// Cria a imagem e sobrescreve a original
imagegif( $nova_imagem, $caminho_imagem );

// Remove as imagens temporárias
imagedestroy($imagem);
imagedestroy($nova_imagem);
?>

Mas tome muito cuidado, se você fizer algo errado, não terá como voltar atrás.

Acessando a imagem dinamicamente

Para acessar a imagem, basta acessar o segundo parâmetro das funções: imagejpeg, imagepng ou imagegif.

Veja:

<?php
// O caminho da nossa imagem no servidor
$caminho_imagem = 'teste.gif';

// Retorna o identificador da imagem
$imagem = imagecreatefromgif($caminho_imagem);

// Cria duas variáveis com a largura e altura da imagem
list( $largura, $altura ) = getimagesize( $caminho_imagem );

// Nova largura e altura
$proporcao = 0.5;
$nova_largura = $largura * $proporcao;
$nova_altura = $altura * $proporcao;

// Cria uma nova imagem em branco
$nova_imagem = imagecreatetruecolor( $nova_largura, $nova_altura );

// Copia a imagem para a nova imagem com o novo tamanho
imagecopyresampled(
    $nova_imagem, // Nova imagem 
    $imagem, // Imagem original
    0, // Coordenada X da nova imagem
    0, // Coordenada Y da nova imagem 
    0, // Coordenada X da imagem 
    0, // Coordenada Y da imagem  
    $nova_largura, // Nova largura
    $nova_altura, // Nova altura
    $largura, // Largura original
    $altura // Altura original
);

// Caminho da nova imagem
$caminho_nova_imagem = 'nova_imagem.jpg';

// Cria a imagem e sobrescreve a original
imagegif( $nova_imagem, $caminho_nova_imagem );

// Remove as imagens temporárias
imagedestroy($imagem);
imagedestroy($nova_imagem);

// Mostro a imagem criada na tela
echo '<img src="' . $caminho_nova_imagem . '">';
?>

 Classe para redimensionar imagens com PHP

Para facilitar sua vida, criei uma classe que faz todo o processo de redimensionamento de imagens com PHP para você. Essa classe somente redimensiona imagens em JPG, PNG e GIF.

Veja seu código:

<?php
/**
 * TutsupRedimensionaImagem - Tutsup Redimensiona Imagem
 *
 * Classe para redimensionar imagens.
 */
class TutsupRedimensionaImagem
{

    /*-------------------------------------------------------------------------*
     * Público
    /*------------------------------------------------------------------------*/
    
    /* Configurações públicas referentes à imagem */
    public $imagem, 
           $imagem_destino, 
           $largura, 
           $altura, 
           $qualidade = 75; // Max. 100
    
    // Nosso erro
    public $erro;
    
    /* Extensões permitidas */
    public $extensoes = array ( 'jpg', 'png', 'gif' );

    /*-------------------------------------------------------------------------*
     * Privado
    /*------------------------------------------------------------------------*/

    /* Extensão da imagem enviada */
    private $extensao;
    
    /* Configurações privadas referentes à nova imagem */
    private $r_imagem, 
            $nova_altura, 
            $nova_largura, 
            $largura_original, 
            $altura_original;

    /*-------------------------------------------------------------------------*
     * Métodos Públicos
    /*------------------------------------------------------------------------*/
    
    /**
     * Executa o redimensionamento da imagem
     *
     * @return string|bool O endereço da imagem ou false
     */
    public function executa() { 
        
        /* Captura a extensão da imagem enviada */
        $extensao = strrchr( $this->imagem, '.' );
        
        /* Garante que a extensão terá apenas letras minúsculas */
        $extensao = strtolower( $extensao );
        
        /* Remove o ponto da extensão */
        $extensao = str_replace('.', '', $extensao);
        
        /* 
        Se a extensão enviada não estiver entre as extensões permitidas, 
        preenche o erro e retorna falso
        */
        if ( ! in_array( $extensao, $this->extensoes ) ) {
            $this->erro = 'Arquivo não permitido.';
            return;
        }
        
        /* 
        Se a imagem não existir, preenche o erro e retorna falso
        */
        if ( ! file_exists( $this->imagem ) ) {
            $this->erro = 'Arquivo inexistente.';
            return;
        }
        
        /* Se a extensão for jpg */
        if ( 'jpg' === $extensao ) {
            
            /* Cria uma imagem jpg a partir da imagem enviada */
            $this->r_imagem = imagecreatefromjpeg($this->imagem);
            
            /* Cria a nova imagem com o tamanho correto */
            $imagem_redimensionada = $this->redimensiona();
            
            /* Se a nova imagem não for criada, preenche o erro e retorna */
            if ( ! $imagem_redimensionada ) {
                $this->erro = 'Erro ao redimensionar imagem.';
                return;
            }
            
            /* Copia a nova imagem da imagem antiga com o tamanho correto */
            imagecopyresampled(
                $imagem_redimensionada, 
                $this->r_imagem, 
                0, 
                0, 
                0, 
                0, 
                $this->nova_largura, 
                $this->nova_altura,
                $this->largura_original, 
                $this->altura_original
            
            );
            
            /* 
            Se a imagem de destino não for configurada, vamos exibir a nova 
            imagem na tela 
            */
            if ( ! $this->imagem_destino ) {
                header('Content-type: image/jpg');
            }        
            
            /* Cria a imagem ou exibe na tela */
            imagejpeg ( 
                $imagem_redimensionada, 
                $this->imagem_destino, 
                $this->qualidade 
            );
            
        } /* jpg */
        
        /* Se a extensão for png */
        elseif ( 'png' === $extensao ) {
        
            /* Cria uma imagem png a partir da imagem enviada */
            $this->r_imagem = imagecreatefrompng($this->imagem);
            
            /* Cria a nova imagem com o tamanho correto */
            $imagem_redimensionada = $this->redimensiona();
            
            /* Se a nova imagem não for criada, preenche o erro e retorna */
            if ( ! $imagem_redimensionada ) {
                $this->erro = 'Erro ao redimensionar imagem.';
                return;
            }
            
            /* 
            Se a imagem de destino não for configurada, vamos exibir a nova 
            imagem na tela 
            */
            if ( ! $this->imagem_destino ) {
                header('Content-type: image/png');
            }        
            
            /* Copia a nova imagem da imagem antiga com o tamanho correto */
            imagecopyresampled(
                $imagem_redimensionada, 
                $this->r_imagem, 
                0, 
                0, 
                0, 
                0, 
                $this->nova_largura, 
                $this->nova_altura, 
                $this->largura_original, 
                $this->altura_original
            
            );
            
            /* Para o formato png, a qualidade vai de 0 a 9 */
            $this->qualidade = $this->qualidade / 10;
            $this->qualidade = $this->qualidade > 9 ? 
                               9 : 
                               floor( $this->qualidade );
            
            /* Cria a imagem ou exibe na tela */
            imagepng ( 
                $imagem_redimensionada, 
                $this->imagem_destino, 
                $this->qualidade 
            );
            
        } /* png */
        
        /* Se a extensão for gif */
        elseif ( 'gif' === $extensao ) {
        
            /* Cria uma imagem gif a partir da imagem enviada */
            $this->r_imagem = imagecreatefromgif($this->imagem);
            
            /* Cria a nova imagem com o tamanho correto */
            $imagem_redimensionada = $this->redimensiona();

            /* Se a nova imagem não for criada, preenche o erro e retorna */
            if ( ! $imagem_redimensionada ) {
                $this->erro = 'Erro ao redimensionar imagem.';
                return;
            }
            
            /* 
            Se a imagem de destino não for configurada, vamos exibir a nova 
            imagem na tela 
            */
            if ( ! $this->imagem_destino ) {
                header('Content-type: image/png');
            }        
            
            /* Copia a nova imagem da imagem antiga com o tamanho correto */
            imagecopyresampled(
                $imagem_redimensionada, 
                $this->r_imagem, 
                0, 
                0, 
                0, 
                0, 
                $this->nova_largura, 
                $this->nova_altura, 
                $this->largura_original, 
                $this->altura_original
            
            );
            
            /* Cria a imagem ou exibe na tela */
            imagegif( $imagem_redimensionada, $this->imagem_destino );
            
        } /* gif */
        
        /* Destroy as imagens geradas */
        if ( $imagem_redimensionada ) {
            imagedestroy( $imagem_redimensionada );
        }
        
        if ( $this->r_imagem ) {
            imagedestroy( $this->r_imagem );
        } 
        
        /* Retorna o endereço da imagem */
        return $this->imagem_destino;
        
    } /* executa() */
    
    /*-------------------------------------------------------------------------*
     * Métodos Privados
    /*------------------------------------------------------------------------*/

    /* Cria a nova imagem redimensionada */
    final private function redimensiona() {
    
        /* Se não for resource, termina aqui */
        if( ! is_resource( $this->r_imagem ) ) return;
        
        /* Obtém a largura e altura da imagem */
        list($largura, $altura) = getimagesize( $this->imagem );
        
        /* Configura as propriedades */
        $this->largura_original = $largura;
        $this->altura_original = $altura;
        
        /* Configura a nova largura */
        $this->nova_largura = 
        $this->largura ? $this->largura : 
        floor ( ( $this->largura_original / $this->altura_original ) * 
        $this->altura );
        
        /* Configura a nova altura */
        $this->nova_altura = 
        $this->altura ? $this->altura : 
        floor( ( $this->altura_original / $this->largura_original ) * 
        $this->largura );
        
        /* Retorna a nova imagem criada */
        return imagecreatetruecolor( $this->nova_largura, $this->nova_altura );
        
    } /* redimensiona() */
    
    
} /* TutsupRedimensionaImagem */

Todo o código está comentado acima.

Veja como utilizar nossa classe (ela faz tudo por você, somente é necessário indicar o que deseja que seja feito).

<?php
/* Inclui a classe */
require 'classes/TutsupRedimensionaImagem.php';

/* Cria a instancia da classe */
$imagem = new TutsupRedimensionaImagem();

/* Configura a imagem que vamos redimensionar */
$imagem->imagem = 'imagens/teste.png';

/* 
Configura a imagem de destino. Se você for apenas exibir uma imagem
temporária, comente esta linha
*/
$imagem->imagem_destino = 'arquivos/nova_imagem.png';

/* 
Se uma largura for definida, você pode deixar a classe calcular o aspect 
ratio da imagem deixando a altura zerada. O mesmo vale para a largura, porém,
uma altura deverá existir (uma das duas deve ser definida).

Você também pode configurar as duas, neste caso você força a imagem a ter o 
tamanho desejado
*/
$imagem->largura = 520;

/* A nova altura será gerada automaticamente. */
$imagem->altura = 0;

/* Qualidade de 0 a 100 */
$imagem->qualidade = 100;

/* Gera a nova imagem */
$nova_imagem = $imagem->executa();

/* Se não for uma imagem temporária, você poderá exibi-la assim */
if ( $imagem->imagem_destino && $nova_imagem ) {
    echo "<img src='{$nova_imagem}'>";
}

/* Se você quiser ver se algum erro ocorreu, utilize o seguinte. */
if ( $imagem->erro ) echo $imagem->erro;
?>

 Download da classe para redimensionar imagens com PHP

Você pode baixar essa classe já pronta e com exemplos no link abaixo:

TutsupRedimensionaImagem.zip

Existe um exemplo de utilização já pronto no arquivo index.php.

Caso queira contribuir e ajudar a melhorar essa classe simples, acesso seu código no github.

Concluindo

Conforme eu disse anteriormente, em algum momento do seu código será necessário redimensionar imagens e este artigo vai lhe guiar pelo processo inicial sobre como fazer o serviço.

Mas lembre-se, conhecimento nunca é demais, e há milhares de coisas legais que você pode fazer com a biblioteca GD, incluindo criar suas próprias imagens do zero. Continue ficando fera no PHP seguindo o tutsup.

Te vejo nos próximos tutoriais.

Fazer upload de arquivos via FTP com PHP é bastante fácil. Com a ajuda de algumas funções e algumas verificações no arquivo que você está enviando, leva apenas alguns minutos para criar um script que envia seus arquivos de maneira bem rápida.

De fato, você vai gastar mais tempo analisando o arquivo que o usuário envia através do formulário HTML, do que enviando o arquivo para o servidor.

Neste tutorial vamos criar um script que envia arquivos para o servidor via conexão FTP. O PHP nos fornecerá algumas funções para realizar toda a conexão e transferência do arquivo.

Vamos verificar apenas a extensão e tamanho do arquivo enviado, sinta-se à vontade para modificar o script conforme sua necessidade.

Como funciona o Upload de arquivos via FTP com PHP?

Vamos precisar de apenas dois arquivos:

  • index.php – O arquivo que conterá o nosso formulário HTML para o usuário enviar o arquivo;
  • envia.php – O arquivo que envia o arquivo para o servidor utilizando conexão FTP;

O arquivo envia.php estará dividido em 4 etapas, todas você verá mais adiante neste artigo.

Arquivo index.php (formulário HTML)

Nosso formulário HTML é extremamente simples, veja:

<form action="envia.php" method="post" enctype="multipart/form-data">
	Arquivo: <input type="file" name="arquivo">
	<input type="submit" value="Enviar">
</form>

Você deve se preocupar com alguns fatores sobre o formulário em si, não vou entrar em detalhes sobre eles aqui, pois já falamos sobre isso no artigo:

Portanto, leia o artigo acima para mais detalhes.

Arquivo envia.php (faz o upload via FTP)

O arquivo envia.php está dividido em quatro etapas. Vamos passar por todas elas abaixo:

Configurações do Envio de arquivos

Vamos realizar nossas configurações logo no cabeçalho do arquivo, assim não precisaremos editar o restante quando formos criar novos formulários.

// Configura o tempo limite para ilimitado
set_time_limit(0);

/*-----------------------------------------------------------------------------*
 * Parte 1: Configurações do Envio de arquivos via FTP com PHP
/*----------------------------------------------------------------------------*/

// IP do Servidor FTP
$servidor_ftp = '127.0.0.1';

// Usuário e senha para o servidor FTP
$usuario_ftp = 'luizotavio';
$senha_ftp   = 'minhasenha';

// Extensões de arquivos permitidas
$extensoes_autorizadas = array( '.exe', '.jpg', '.mp4', '.mkv', '.txt' );

// Caminho da pasta FTP
$caminho = 'arquivos/';

/* 
Se quiser limitar o tamanho dos arquivo, basta colocar o tamanho máximo 
em bytes. Zero é ilimitado
*/
$limitar_tamanho = 0;

/* 
Qualquer valor diferente de 0 (zero) ou false, permite que o arquivo seja 
sobrescrito
*/
$sobrescrever = 0;

Você pode visualizar tudo o que a primeira parte faz nos comentários do código acima.

Configurações do arquivo

As configurações do arquivo, são simplesmente os dados do arquivo enviado, como nome, tamanho e coisas do tipo.

/*-----------------------------------------------------------------------------*
 * Parte 2: Configurações do arquivo
/*----------------------------------------------------------------------------*/

// Verifica se o arquivo não foi enviado. Se não; termina o script.
if ( ! isset( $_FILES['arquivo'] ) ) {
	exit('Nenhum arquivo enviado!');
}

// Aqui o arquivo foi enviado e vamos configurar suas variáveis
$arquivo = $_FILES['arquivo'];

// Nome do arquivo enviado
$nome_arquivo = $arquivo['name'];

// Tamanho do arquivo enviado
$tamanho_arquivo = $arquivo['size'];

// Nome do arquivo temporário
$arquivo_temp = $arquivo['tmp_name'];

// Extensão do arquivo enviado
$extensao_arquivo = strrchr( $nome_arquivo, '.' );

// O destino para qual o arquivo será enviado
$destino = $caminho . $nome_arquivo;

Dentre as funções utilizadas, temos:

  • isset – Verifica se a variável está configurada;
  • strrchr – Encontra a ultima ocorrência de um caractere em uma string ;
  • exit – Termina o script onde essa função for apresentada

Verificações do arquivo enviado

Agora precisaremos verifica o arquivo enviado. Veja:

/*-----------------------------------------------------------------------------*
 *  Parte 3: Verificações do arquivo enviado
/*----------------------------------------------------------------------------*/

/* 
Se a variável $sobrescrever não estiver configurada, assumimos que não podemos 
sobrescrever o arquivo. Então verificamos se o arquivo existe. Se existir; 
terminamos aqui. 
*/

if ( ! $sobrescrever && file_exists( $destino ) ) {
	exit('Arquivo já existe.');
}

/* 
Se a variável $limitar_tamanho tiver valor e o tamanho do arquivo enviado for
maior do que o tamanho limite, terminado aqui.
*/

if ( $limitar_tamanho && $limitar_tamanho < $tamanho_arquivo ) {
	exit('Arquivo muito grande.');
}

/* 
Se as $extensoes_autorizadas não estiverem vazias e a extensão do arquivo não 
estiver entre as extensões autorizadas, terminamos aqui.
*/

if ( ! empty( $extensoes_autorizadas ) && ! in_array( $extensao_arquivo, $extensoes_autorizadas ) ) {
	exit('Tipo de arquivo não permitido.');
}

Agora podemos fazer a conexão e enviar o arquivo.

Conexão e upload via FTP com PHP

Os links para mais detalhes sobre as funções utilizadas estão ao abaixo do código. O restante está comentado no mesmo:

/*-----------------------------------------------------------------------------*
 * Parte 4: Conexão FTP
/*----------------------------------------------------------------------------*/

// Realiza a conexão
$conexao_ftp = ftp_connect( $servidor_ftp );

// Tenta fazer login
$login_ftp = @ftp_login( $conexao_ftp, $usuario_ftp, $senha_ftp );

// Se não conseguir fazer login, termina aqui
if ( ! $login_ftp ) {
	exit('Usuário ou senha FTP incorretos.');
}

// Envia o arquivo
if ( @ftp_put( $conexao_ftp, $destino, $arquivo_temp, FTP_BINARY ) ) {
	// Se for enviado, mostra essa mensagem
	echo 'Arquivo enviado com sucesso!';
} else {
	// Se não for enviado, mostra essa mensagem
	echo 'Erro ao enviar arquivo!';
}

// Fecha a conexão FTP
ftp_close( $conexao_ftp );

Dentre as funções utilizadas temos:

Código completo do arquivo envia.php

Veja nosso código completo:

<?php
// Configura o tempo limite para ilimitado
set_time_limit(0);

/*-----------------------------------------------------------------------------*
 * Parte 1: Configurações do Envio de arquivos via FTP com PHP
/*----------------------------------------------------------------------------*/

// IP do Servidor FTP
$servidor_ftp = '127.0.0.1';

// Usuário e senha para o servidor FTP
$usuario_ftp = 'luizotavio';
$senha_ftp   = 'minhasenha';

// Extensões de arquivos permitidas
$extensoes_autorizadas = array( '.exe', '.jpg', '.mp4', '.mkv', '.txt' );

// Caminho da pasta FTP
$caminho = 'arquivos/';

/* 
Se quiser limitar o tamanho dos arquivo, basta colocar o tamanho máximo 
em bytes. Zero é ilimitado
*/
$limitar_tamanho = 0;

/* 
Qualquer valor diferente de 0 (zero) ou false, permite que o arquivo seja 
sobrescrito
*/
$sobrescrever = 0;

/*-----------------------------------------------------------------------------*
 * Parte 2: Configurações do arquivo
/*----------------------------------------------------------------------------*/

// Verifica se o arquivo não foi enviado. Se não; termina o script.
if ( ! isset( $_FILES['arquivo'] ) ) {
	exit('Nenhum arquivo enviado!');
}

// Aqui o arquivo foi enviado e vamos configurar suas variáveis
$arquivo = $_FILES['arquivo'];

// Nome do arquivo enviado
$nome_arquivo = $arquivo['name'];

// Tamanho do arquivo enviado
$tamanho_arquivo = $arquivo['size'];

// Nome do arquivo temporário
$arquivo_temp = $arquivo['tmp_name'];

// Extensão do arquivo enviado
$extensao_arquivo = strrchr( $nome_arquivo, '.' );

// O destino para qual o arquivo será enviado
$destino = $caminho . $nome_arquivo;

/*-----------------------------------------------------------------------------*
 *  Parte 3: Verificações do arquivo enviado
/*----------------------------------------------------------------------------*/

/* 
Se a variável $sobrescrever não estiver configurada, assumimos que não podemos 
sobrescrever o arquivo. Então verificamos se o arquivo existe. Se existir; 
terminamos aqui. 
*/

if ( ! $sobrescrever && file_exists( $destino ) ) {
	exit('Arquivo já existe.');
}

/* 
Se a variável $limitar_tamanho tiver valor e o tamanho do arquivo enviado for
maior do que o tamanho limite, terminado aqui.
*/

if ( $limitar_tamanho && $limitar_tamanho < $tamanho_arquivo ) {
	exit('Arquivo muito grande.');
}

/* 
Se as $extensoes_autorizadas não estiverem vazias e a extensão do arquivo não 
estiver entre as extensões autorizadas, terminamos aqui.
*/

if ( ! empty( $extensoes_autorizadas ) && ! in_array( $extensao_arquivo, $extensoes_autorizadas ) ) {
	exit('Tipo de arquivo não permitido.');
}

/*-----------------------------------------------------------------------------*
 * Parte 4: Conexão FTP
/*----------------------------------------------------------------------------*/

// Realiza a conexão
$conexao_ftp = ftp_connect( $servidor_ftp );

// Tenta fazer login
$login_ftp = @ftp_login( $conexao_ftp, $usuario_ftp, $senha_ftp );

// Se não conseguir fazer login, termina aqui
if ( ! $login_ftp ) {
	exit('Usuário ou senha FTP incorretos.');
}

// Envia o arquivo
if ( @ftp_put( $conexao_ftp, $destino, $arquivo_temp, FTP_BINARY ) ) {
	// Se for enviado, mostra essa mensagem
	echo 'Arquivo enviado com sucesso!';
} else {
	// Se não for enviado, mostra essa mensagem
	echo 'Erro ao enviar arquivo!';
}

// Fecha a conexão FTP
ftp_close( $conexao_ftp );

 Download

Caso queira baixar este script para completar seus estudos, utilize o link abaixo:

Download envia_arquivos_FTP_PHP.zip

É o mesmo script descrito no artigo acima.

Dúvidas?

Em caso de dúvidas, não hesite em deixar seu comentário. Teremos o maior prazer em ajudar.

Para terminar nossa aplicação com estrutura MVC em PHP, vamos criar um sistema de cadastro de notícias bem simples, com campos de título, data, autor, texto e URL da imagem.

Além disso, criaremos uma área administrativa para gerenciar as notícias, onde poderemos criar, apagar, editar e listar notícias cadastradas.

Este é apenas um exemplo sobre como iremos utilizar nossa aplicação MVC em PHP. A partir desse tutorial você estará apto a criar seus próprios modelos, controladores e views simplesmente seguindo o mesmo modelo.

Download

Antes de qualquer coisa, faça o download da aplicação e acompanhe em seu computador. Segue o link para download:

Caso queira contribuir com o projeto, acesso no Github:

Se tiver perdido alguma parte desse tutorial, deixo os links para facilitar sua vida:

Então vamos codificar um pouco…

Criando o controller para as notícias

Primeiramente vamos criar o nosso controller, portando acesse a pasta “controllers” e crie um arquivo chamado “noticias-controller.php”.

Neste controller teremos que ter duas ações:

  • index (pública) – Lista as notícias na página e não precisa de usuário e senha para o acesso;
  • adm (restrita) – Gerenciamento das notícias – CRUD com PDO

Veja o código do controller:

<?php
/**
 * NoticiasController - Controller de exemplo
 *
 * @package TutsupMVC
 * @since 0.1
 */
class NoticiasController extends MainController
{

   /**
    * $login_required
    *
    * Se a página precisa de login
    *
    * @access public
    */
    public $login_required = false;

   /**
    * $permission_required
    *
    * Permissão necessária
    *
    * @access public
    */
    public $permission_required;

   /**
    * INDEX
    *
    * Carrega a página "/views/noticias/index.php"
    */
    public function index() {
	// Título da página
	$this->title = 'Notícias';
	
	// Carrega o modelo para este view
        $modelo = $this->load_model('noticias/noticias-adm-model');
				
	/** Carrega os arquivos do view **/
		
	// /views/_includes/header.php
        require ABSPATH . '/views/_includes/header.php';
		
	// /views/_includes/menu.php
        require ABSPATH . '/views/_includes/menu.php';
		
	// /views/noticias/index.php
        require ABSPATH . '/views/noticias/noticias-view.php';
		
	// /views/_includes/footer.php
        require ABSPATH . '/views/_includes/footer.php';
		
    } // index
	
   /**
    * ADM
    *
    * Carrega a página "/views/noticias/noticias-adm-view.php"
    */
    public function adm() {
		// Page title
		$this->title = 'Gerenciar notícias';
		$this->permission_required = 'gerenciar-noticias';
		
		// Verifica se o usuário está logado
		if ( ! $this->logged_in ) {
		
			// Se não; garante o logout
			$this->logout();
			
			// Redireciona para a página de login
			$this->goto_login();
			
			// Garante que o script não vai passar daqui
			return;
		
		}
		
		// Verifica se o usuário tem a permissão para acessar essa página
		if (!$this->check_permissions($this->permission_required, $this->userdata['user_permissions'])) {
		
			// Exibe uma mensagem
			echo 'Você não tem permissões para acessar essa página.';
			
			// Finaliza aqui
			return;
		}
	
	// Carrega o modelo para este view
        $modelo = $this->load_model('noticias/noticias-adm-model');
		
	/** Carrega os arquivos do view **/
		
	// /views/_includes/header.php
        require ABSPATH . '/views/_includes/header.php';
		
	// /views/_includes/menu.php
        require ABSPATH . '/views/_includes/menu.php';
		
	// /views/noticias/index.php
        require ABSPATH . '/views/noticias/noticias-adm-view.php';
		
	// /views/_includes/footer.php
        require ABSPATH . '/views/_includes/footer.php';
		
    } // adm
	
} // class NoticiasController

Veja que temos duas ações agora, index e adm. Ambas serão acessadas pelas URLs:

  • index: dominio.com/noticias/
  • adm: dominio.com/noticias/adm/

Agora vamos criar o modelo para as notícias.

Criando o model para as notícias

Nosso model será compartilhado pelos dois views que teremos, um para a ação “adm” outro para “index”.

Lembre-se: Modelos ficam dentro da pasta models separados por pastas. Nosso model estará dentro da pasta noticias com o nome de noticias-adm-model.php.

Veja seu código:

<?php 
/**
 * Modelo para gerenciar notícias
 *
 * @package TutsupMVC
 * @since 0.1
 */
class NoticiasAdmModel extends MainModel
{

	/**
	 * $posts_per_page
	 *
	 * Receberá o número de posts por página para configurar a listagem de 
	 * notícias. Também utilizada na paginação. 
	 *
	 * @access public
	 */
	public $posts_por_pagina = 5;
	
	/**
	 * Construtor para essa classe
	 *
	 * Configura o DB, o controlador, os parâmetros e dados do usuário.
	 *
	 * @since 0.1
	 * @access public
	 * @param object $db Objeto da nossa conexão PDO
	 * @param object $controller Objeto do controlador
	 */
	public function __construct( $db = false, $controller = null ) {
		// Configura o DB (PDO)
		$this->db = $db;
		
		// Configura o controlador
		$this->controller = $controller;

		// Configura os parâmetros
		$this->parametros = $this->controller->parametros;

		// Configura os dados do usuário
		$this->userdata = $this->controller->userdata;
	}
	
	/**
	 * Lista notícias
	 *
	 * @since 0.1
	 * @access public
	 * @return array Os dados da base de dados
	 */
	public function listar_noticias () {
	
		// Configura as variáveis que vamos utilizar
		$id = $where = $query_limit = null;
		
		// Verifica se um parâmetro foi enviado para carregar uma notícia
		if ( is_numeric( chk_array( $this->parametros, 0 ) ) ) {
			
			// Configura o ID para enviar para a consulta
			$id = array ( chk_array( $this->parametros, 0 ) );
			
			// Configura a cláusula where da consulta
			$where = " WHERE noticia_id = ? ";
		}
		
		// Configura a página a ser exibida
		$pagina = ! empty( $this->parametros[1] ) ? $this->parametros[1] : 1;
		
		// A paginação inicia do 0
		$pagina--;
		
		// Configura o número de posts por página
		$posts_por_pagina = $this->posts_por_pagina;
		
		// O offset dos posts da consulta
		$offset = $pagina * $posts_por_pagina;
		
		/* 
		Esta propriedade foi configurada no noticias-adm-model.php para
		prevenir limite ou paginação na administração.
		*/
		if ( empty ( $this->sem_limite ) ) {
		
			// Configura o limite da consulta
			$query_limit = " LIMIT $offset,$posts_por_pagina ";
		
		}
		
		// Faz a consulta
		$query = $this->db->query(
			'SELECT * FROM noticias ' . $where . ' ORDER BY noticia_id DESC' . $query_limit,
			$id
		);
		
		// Retorna
		return $query->fetchAll();
	} // listar_noticias
	
	/**
	 * Obtém a notícia e atualiza os dados se algo for postado
	 *
	 * Obtém apenas uma notícia da base de dados para preencher o formulário de
	 * edição.
	 * Configura a propriedade $this->form_data.
	 *
	 * @since 0.1
	 * @access public
	 */
	public function obtem_noticia () {
		
		// Verifica se o primeiro parâmetro é "edit"
		if ( chk_array( $this->parametros, 0 ) != 'edit' ) {
			return;
		}
		
		// Verifica se o segundo parâmetro é um número
		if ( ! is_numeric( chk_array( $this->parametros, 1 ) ) ) {
			return;
		}
		
		// Configura o ID da notícia
		$noticia_id = chk_array( $this->parametros, 1 );
		
		/* 
		Verifica se algo foi postado e se está vindo do form que tem o campo
		insere_noticia.
		
		Se verdadeiro, atualiza os dados conforme a requisição.
		*/
		if ( 'POST' == $_SERVER['REQUEST_METHOD'] && ! empty( $_POST['insere_noticia'] ) ) {
		
			// Remove o campo insere_notica para não gerar problema com o PDO
			unset($_POST['insere_noticia']);
			
			// Verifica se a data foi enviada
			$data = chk_array( $_POST, 'noticia_data' );
			
			/*
			Inverte a data para os formatos dd-mm-aaaa hh:mm:ss
			ou aaaa-mm-dd hh:mm:ss
			*/
			$nova_data = $this->inverte_data( $data );
			
			// Adiciona a data no $_POST		
			$_POST['noticia_data'] = $nova_data;
			
			// Tenta enviar a imagem
			$imagem = $this->upload_imagem();
			
			// Verifica se a imagem foi enviada
			if ( $imagem ) {
				// Adiciona a imagem no $_POST
				$_POST['noticia_imagem'] = $imagem;
			}
			
			// Atualiza os dados
			$query = $this->db->update('noticias', 'noticia_id', $noticia_id, $_POST);
			
			// Verifica a consulta
			if ( $query ) {
				// Retorna uma mensagem
				$this->form_msg = '<p class="success">Notícia atualizada com sucesso!</p>';
			}
			
		}
		
		// Faz a consulta para obter o valor
		$query = $this->db->query(
			'SELECT * FROM noticias WHERE noticia_id = ? LIMIT 1',
			array( $noticia_id )
		);
		
		// Obtém os dados
		$fetch_data = $query->fetch();
		
		// Se os dados estiverem nulos, não faz nada
		if ( empty( $fetch_data ) ) {
			return;
		}
		
		// Configura os dados do formulário
		$this->form_data = $fetch_data;
		
	} // obtem_noticia
	
	/**
	 * Insere notícias
	 *
	 * @since 0.1
	 * @access public
	 */
	public function insere_noticia() {
	
		/* 
		Verifica se algo foi postado e se está vindo do form que tem o campo
		insere_noticia.
		*/
		if ( 'POST' != $_SERVER['REQUEST_METHOD'] || empty( $_POST['insere_noticia'] ) ) {
			return;
		}
		
		/*
		Para evitar conflitos apenas inserimos valores se o parâmetro edit
		não estiver configurado.
		*/
		if ( chk_array( $this->parametros, 0 ) == 'edit' ) {
			return;
		}
		
		// Só pra garantir que não estamos atualizando nada
		if ( is_numeric( chk_array( $this->parametros, 1 ) ) ) {
			return;
		}
			
		// Tenta enviar a imagem
		$imagem = $this->upload_imagem();
		
		// Verifica se a imagem foi enviada
		if ( ! $imagem ) {
			return;		
		}
		
		// Remove o campo insere_notica para não gerar problema com o PDO
		unset($_POST['insere_noticia']);
		
		// Insere a imagem em $_POST
		$_POST['noticia_imagem'] = $imagem;
		
		// Configura a data
		$data = chk_array( $_POST, 'noticia_data' );
		$nova_data = $this->inverte_data( $data );
					
		// Adiciona a data no POST
		$_POST['noticia_data'] = $nova_data;
		
		// Insere os dados na base de dados
		$query = $this->db->insert( 'noticias', $_POST );
		
		// Verifica a consulta
		if ( $query ) {
		
			// Retorna uma mensagem
			$this->form_msg = '<p class="success">Notícia atualizada com sucesso!</p>';
			return;
			
		} 
		
		// :(
		$this->form_msg = '<p class="error">Erro ao enviar dados!</p>';

	} // insere_noticia
	
	/**
	 * Apaga a notícia
	 *
	 * @since 0.1
	 * @access public
	 */
	public function apaga_noticia () {
		
		// O parâmetro del deverá ser enviado
		if ( chk_array( $this->parametros, 0 ) != 'del' ) {
			return;
		}
		
		// O segundo parâmetro deverá ser um ID numérico
		if ( ! is_numeric( chk_array( $this->parametros, 1 ) ) ) {
			return;
		}
		
		// Para excluir, o terceiro parâmetro deverá ser "confirma"
		if ( chk_array( $this->parametros, 2 ) != 'confirma' ) {
		
			// Configura uma mensagem de confirmação para o usuário
			$mensagem  = '<p class="alert">Tem certeza que deseja apgar a notícia?</p>';
			$mensagem .= '<p><a href="' . $_SERVER['REQUEST_URI'] . '/confirma/">Sim</a> | ';
			$mensagem .= '<a href="' . HOME_URI . '/noticias/adm/">Não</a></p>';
			
			// Retorna a mensagem e não excluir
			return $mensagem;
		}
		
		// Configura o ID da notícia
		$noticia_id = (int)chk_array( $this->parametros, 1 );
		
		// Executa a consulta
		$query = $this->db->delete( 'noticias', 'noticia_id', $noticia_id );
		
		// Redireciona para a página de administração de notícias
		echo '<meta http-equiv="Refresh" content="0; url=' . HOME_URI . '/noticias/adm/">';
		echo '<script type="text/javascript">window.location.href = "' . HOME_URI . '/noticias/adm/";</script>';
		
	} // apaga_noticia
	
	/**
	 * Envia a imagem
	 *
	 * @since 0.1
	 * @access public
	 */
	public function upload_imagem() {
	
		// Verifica se o arquivo da imagem existe
		if ( empty( $_FILES['noticia_imagem'] ) ) {
			return;
		}
		
		// Configura os dados da imagem
		$imagem         = $_FILES['noticia_imagem'];
		
		// Nome e extensão
		$nome_imagem    = strtolower( $imagem['name'] );
		$ext_imagem     = explode( '.', $nome_imagem );
		$ext_imagem     = end( $ext_imagem );
		$nome_imagem    = preg_replace( '/[^a-zA-Z0-9]/', '', $nome_imagem);
		$nome_imagem   .= '_' . mt_rand() . '.' . $ext_imagem;
		
		// Tipo, nome temporário, erro e tamanho
		$tipo_imagem    = $imagem['type'];
		$tmp_imagem     = $imagem['tmp_name'];
		$erro_imagem    = $imagem['error'];
		$tamanho_imagem = $imagem['size'];
		
		// Os mime types permitidos
		$permitir_tipos  = array(
			'image/bmp',
			'image/x-windows-bmp',
			'image/gif',
			'image/jpeg',
			'image/pjpeg',
			'image/png',
		);
		
		// Verifica se o mimetype enviado é permitido
		if ( ! in_array( $tipo_imagem, $permitir_tipos ) ) {
			// Retorna uma mensagem
			$this->form_msg = '<p class="error">Você deve enviar uma imagem.</p>';
			return;
		}
		
		// Tenta mover o arquivo enviado
		if ( ! move_uploaded_file( $tmp_imagem, UP_ABSPATH . '/' . $nome_imagem ) ) {
			// Retorna uma mensagem
			$this->form_msg = '<p class="error">Erro ao enviar imagem.</p>';
			return;
		}
		
		// Retorna o nome da imagem
		return $nome_imagem;
		
	} // upload_imagem
	
	/**
	 * Paginação
	 *
	 * @since 0.1
	 * @access public
	 */
	public function paginacao () {
	
		/* 
		Verifica se o primeiro parâmetro não é um número. Se for é um single
		e não precisa de paginação.
		*/
		if ( is_numeric( chk_array( $this->parametros, 0) ) ) {	
			return;
		}
		
		// Obtém o número total de notícias da base de dados
		$query = $this->db->query(
			'SELECT COUNT(*) as total FROM noticias '
		);
		$total = $query->fetch();
		$total = $total['total'];
		
		// Configura o caminho para a paginação
		$caminho_noticias = HOME_URI . '/noticias/index/page/';
		
		// Itens por página
		$posts_per_page = $this->posts_por_pagina;
		
		// Obtém a última página possível
		$last = ceil($total/$posts_per_page);
		
		// Configura a primeira página
		$first = 1;
		
		// Configura os offsets
		$offset1 = 3;
		$offset2 = 6;
		
		// Página atual
		$current = $this->parametros[1] ? $this->parametros[1] : 1;
		
		// Exibe a primeira página e reticências no início
		if ( $current > 4 ) {
			echo "<a href='$caminho_noticias$first'>$first</a> ... ";
		}
		
		// O primeiro loop toma conta da parte esquerda dos números
		for ( $i = ( $current - $offset1 ); $i < $current; $i++ ) {
			if ( $i > 0 ) {
				echo "<a href='$caminho_noticias$i'>$i</a>";
				
				// Diminiu o offset do segundo loop
				$offset2--;
			}
		}
		
		// O segundo loop toma conta da parte direita dos números
		// Obs.: A primeira expressão realmente não é necessária
		for ( ; $i < $current + $offset2; $i++ ) {
			if ( $i <= $last ) {
				echo "<a href='$caminho_noticias$i'>$i</a>";
			}
		}
		
		// Exibe reticências e a última página no final
		if ( $current <= ( $last - $offset1 ) ) {
			echo " ... <a href='$caminho_noticias$last'>$last</a>";
		}

	} // paginacao
	
} // NoticiasAdmModel

Este é um model bem grande, mas ele fará tudo o que precisamos.

Seus métodos fazem o seguinte:

  • listar_noticias() – Retorna um array com todas as notícias;
  • obtem_noticia() – Obtém uma única notícia. Também atualiza os dados caso algo seja enviado;
  • insere_noticia() – Insere uma notícia na base de dados;
  • apaga_noticia() – Apaga uma notícia da base de dados;
  • upload_imagem() – Faz o upload de imagens se alguma for enviada;
  • paginacao() – Cria uma paginação para apresentar as notícias na página inicial de notícias;

Os métodos estão bem comentados, portanto, leia os comentários e se ficar com dúvidas, basta questionar.

Agora vamos criar os views.

Criando um view para mostrar notícias

Agora vamos criar um dos views que precisamos, o para a área administrativa.

Lembre-se: Views ficam dentro da pasta views separados por pastas. Nosso view estará dentro da pasta noticias com o nome de noticias-adm-view.php e noticias-view.php.

Veja seu o código do arquivo noticias-adm-view.php.

/views/noticias/noticias-adm-view.php

<?php 
// Evita acesso direto a este arquivo
if ( ! defined('ABSPATH')) exit;

// Configura as URLs
$adm_uri = HOME_URI . '/noticias/adm/';
$edit_uri = $adm_uri . 'edit/';
$delete_uri = $adm_uri . 'del/';

		
// Carrega o método para obter uma notícia
$modelo->obtem_noticia();

// Carrega o método para inserir uma notícia
$modelo->insere_noticia();

// Carrega o método para apagar a notícia
$modelo->form_confirma = $modelo->apaga_noticia();

// Remove o limite de valores da lista de notícias
$modelo->sem_limite = true;
?>

<div class="wrap">

	<?php 
	// Mensagem de configuração caso o usuário tente apagar algo
	echo $modelo->form_confirma;
	?>

	<!-- Formulário de edição das notícias -->
	<form method="post" action="" enctype="multipart/form-data">
		<table class="form-table">
			<tr>
				<td>
					Título: <br>
					<input type="text" name="noticia_titulo" value="<?php 
					echo htmlentities( chk_array( $modelo->form_data, 'noticia_titulo') );
					?>" />
				</td>
			</tr>
			<tr>
				<td>
					Imagem: <br>
					<input type="file" name="noticia_imagem" value="" />
				</td>
			</tr>
			<tr>
				<td>
					Data: <br>
					<input type="text" name="noticia_data" value="<?php 
					$data = chk_array( $modelo->form_data, 'noticia_data');
					if ( $data && $data != '0000-00-00 00:00:00' )
					echo date('d-m-Y H:i:s', strtotime( $data ) );
					?>" />
				</td>
			</tr>
			<tr>
				<td>
					Autor: <br>
					<input type="text" name="noticia_autor" value="<?php 
					echo htmlentities( $_SESSION['userdata']['user_name'] );
					?>" />
				</td>
			</tr>
			<tr>
				<td>
					Texto da notícia: <br>
					<textarea name="noticia_texto"><?php
					echo htmlentities( chk_array( $modelo->form_data, 'noticia_texto') );
					?></textarea>
				</td>
			</tr>
			<tr>
				<td colspan="2">
					<?php 
					// Mensagem de feedback para o usuário
					echo $modelo->form_msg;
					?>
					<input type="submit" value="Save" />
				</td>
			</tr>
		</table>
		
		<input type="hidden" name="insere_noticia" value="1" />
	</form>
	
	<!-- LISTA AS NOTICIAS -->
	<?php $lista = $modelo->listar_noticias(); ?>

	<table class="list-table">

		<?php foreach( $lista as $noticia ):?>
			
			<tr>
				<td><?php echo $noticia['noticia_titulo']?></td>
				<td>
					<a href="<?php echo $edit_uri . $noticia['noticia_id']?>">
						Editar
					</a> 
					
					<a href="<?php echo $delete_uri . $noticia['noticia_id']?>">
						Apagar
					</a>
				</td>
			</tr>
			
		<?php endforeach; ?>

	</table>

</div> <!-- .wrap -->

Este view faz todo o sistema de CRUD das notícias utilizando as ações do nosso model.

/views/noticias/noticias-view.php

Veja agora como apresentaremos os dados para o usuário final (este é o view da ação index):

<?php 
// Evita acesso direto a este arquivo
if ( ! defined('ABSPATH')) exit; 
?>

<div class="wrap">

<?php
// Número de posts por página
$modelo->posts_por_pagina = 10;

// Lista notícias
$lista = $modelo->listar_noticias(); 
?>

<?php foreach( $lista as $noticia ):?>
	
	<!-- Título -->
	<h1>
		<a href="<?php echo HOME_URI?>/noticias/index/<?php echo $noticia['noticia_id']?>">
			<?php echo $noticia['noticia_titulo']?>
		</a>
	</h1>

	<?php 
	// Verifica se estamos visualizando uma única notícia
	if ( is_numeric( chk_array( $modelo->parametros, 0 ) ) ): // single
	?>
	
		<p>
		<?php echo $modelo->inverte_data( $noticia['noticia_data'] );?> | 
		<?php echo $noticia['noticia_autor'];?> 
		</p>
		
		<p>
			<img src="<?php 
			echo HOME_URI . '/views/_uploads/' . $noticia['noticia_imagem']; ?>">
		</p>
		
		<?php echo $noticia['noticia_texto'];?>
		
	<?php endif;  // single ?>
	
<?php endforeach; ?>

<?php $modelo->paginacao();?>

</div> <!-- .wrap -->

Isso deverá gerar uma lista com as notícias, links para a página de uma notícia única e uma paginação em baixo.

Dentro da notícia outros campos serão apresentados, como imagem, autor, data e texto.

Veja um exemplo:

Cadastro de notícias

Cadastro de notícias

Campos preenchidos

Campos preenchidos

Notícia sendo visualizada

Notícia sendo visualizada

Lembre-se, isto é apenas um exemplo da funcionalidade do sistema, você deve criar seus próprios modelos, controles e views.

Download e outras partes do artigo

Segue o link para download:

Caso queira contribuir com o projeto, acesso no Github:

Se tiver perdido alguma parte desse tutorial, deixo os links para facilitar sua vida:

Em caso de dúvidas, questione!

Até agora, criamos as partes mais simples do sistema, tais como criar um controller, model e view e exibir o conteúdo na tela, mas e se eu precisar de uma área restrita?

Nossa estrutura MVC foi criada pensando nisso, ou seja, além de você ter a possibilidade de criar partes restritas no seu sistema, também há a possibilidade de criar permissões de acesso para determinados M, V e C.

Além disso, você também pode restringir apenas pedaços de uma página, ou bloquear o acesso completo, fica a seu critério.

Neste artigo você vai aprender a criar o sistema de login, sistema de registro de usuários e MVCs com acesso restrito.

Artigos anteriores

Antes que você continue a ler, é necessário que você tenha visto os artigos anteriores, assim você entenderá melhor o conteúdo que verá aqui:

 

Nos artigos acima eu guio você por toda a estrutura do sistema, detalhando como cada área funciona e interage uma com a outra.

Download

Como estamos criando uma aplicação inteira, são vários arquivos que se encaixam uns nos outros. Se você quiser baixar os dados e ir acompanhando com eles em seu computador, segue o link abaixo:

Caso queira contribuir com o projeto, acesso no Github:

No download acima, a aplicação está praticamente completa. Pode ser que algo seja alterado conforme nossa necessidade, mas vou detalhar tudo no artigo.

Criando o controller de login

Vamos seguir o mesmo modelo da nossa última aula para criar o controller do nosso sistema de login. Felizmente, precisaremos apenas de um controller e um view, já que nossa classe “UserLogin” fará o resto pra gente.

controllers/login-controller.php

Para o controller do nosso login teremos o seguinte:

<?php
/**
 * LoginController - Controller de exemplo
 *
 * @package TutsupMVC
 * @since 0.1
 */
class LoginController extends MainController
{

    /**
    * Carrega a página "/views/login/index.php"
    */
    public function index() {
	// Título da página
	$this->title = 'Login';
		
	// Parametros da função
	$parametros = ( func_num_args() >= 1 ) ? func_get_arg(0) : array();
	
	// Login não tem Model
		
	/** Carrega os arquivos do view **/
		
	// /views/_includes/header.php
        require ABSPATH . '/views/_includes/header.php';
		
	// /views/_includes/menu.php
        require ABSPATH . '/views/_includes/menu.php';
		
	// /views/home/login-view.php
        require ABSPATH . '/views/login/login-view.php';
		
	// /views/_includes/footer.php
        require ABSPATH . '/views/_includes/footer.php';
		
    } // index
	
} // class LoginController

Este controller tem apenas uma ação – index – que será carregada automaticamente quando acessarmos a URL /login/ do nosso sistema. Dentro dessa ação, simplesmente incluímos os arquivos dos views que exibem HTML.

São eles:

/views/_includes/header.php

Este é um cabeçalho HTML comum, veja seu código:

<?php if ( ! defined('ABSPATH')) exit; ?>

<!DOCTYPE html>
<!--[if IE 7]>
<html class="ie ie7" lang="pt-BR">
<![endif]-->
<!--[if IE 8]>
<html class="ie ie8" lang="pt-BR">
<![endif]-->
<!--[if !(IE 7) & !(IE 8)]><!-->
<html lang="pt-BR">
<!--<![endif]-->

<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width">

	<link rel="stylesheet" href="<?php echo HOME_URI;?>/views/_css/style.css">

	<!--[if lt IE 9]>
	<script src="<?php echo HOME_URI;?>/views/_js/scripts.js"></script>
	<![endif]-->

	<title><?php echo $this->title; ?></title>
</head>
<body>

<div class="main-page">

 /views/_includes/menu.php

Outro arquivo HTML comum:

<?php if ( ! defined('ABSPATH')) exit; ?>

<?php if ( $this->login_required && ! $this->logged_in ) return; ?>

<nav class="menu clearfix">
	<ul>
		<li><a href="<?php echo HOME_URI;?>">Home</a></li>
		<li><a href="<?php echo HOME_URI;?>/login/">Login</a></li>
		<li><a href="<?php echo HOME_URI;?>/user-register/">User Register</a></li>
		<li><a href="<?php echo HOME_URI;?>/noticias/">Notícias</a></li>
		<li><a href="<?php echo HOME_URI;?>/noticias/adm/">Notícias Admin</a></li>
		<li><a href="<?php echo HOME_URI;?>/exemplo/">Exemplo básico</a></li>
	</ul>
</nav>

/views/_includes/footer.php

Este tem puramente HTML:

<?php if ( ! defined('ABSPATH')) exit; ?>

</div> <!-- .main-page (header.php) -->

</body>
</html>

 Restringindo acesso direto aos arquivos

É importante que você tenha em mente que usuários mais entendidos sobre PHP e HTML, poderão entender como o sistema funciona e tentar executar arquivos diretamente. Para restringir o acesso a direto a qualquer conteúdo do seu sistema de MVC, adicione a seguinte linha no cabeçalho do seu código:

<?php if ( ! defined('ABSPATH')) exit; ?>

 Criando o view do login

O view do nosso login terá apenas um formulário HTML, veja:

views/login/login-view.php

<?php if ( ! defined('ABSPATH')) exit; ?>

<div class="wrap">

	<form method="post">
		<table class="form-table">
			<tr>
				<td>User</td> 
				<td><input name="userdata[user]"></td>
			</tr>
			<tr>
				<td>Password </td>
				<td><input type="password" name="userdata[user_password]"></td>
			</tr>
			<tr>
				<td colspan="2">
					<input type="submit" value="Enter"> 
				</td>
			</tr>
		</table>
	</form>
	
</div> <!-- .wrap -->

Só isso já é suficiente para que o usuário faça login no sistema e seja redirecionado para a URL que tentou acessar antes do login. O problema é que não temos feedback para o usuário, nenhuma mensagem é apresentada na tela. Para resolver isto, podemos utilizar as propriedades retornadas pela classe UserLogin, veja:

<?php if ( ! defined('ABSPATH')) exit; ?>

<div class="wrap">

<?php
if ( $this->logged_in ) {
	echo '<p class="alert">Logado</p>';
}
?>

	<form method="post">
		<table class="form-table">
			<tr>
				<td>User</td> 
				<td><input name="userdata[user]"></td>
			</tr>
			<tr>
				<td>Password </td>
				<td><input type="password" name="userdata[user_password]"></td>
			</tr>
			<?php
			if ( $this->login_error ) {
				echo '<tr><td colspan="2" class="error">' . $this->login_error . '</td></tr>';
			}
			?>
			<tr>
				<td colspan="2">
					<input type="submit" value="Enter"> 
				</td>
			</tr>
		</table>
	</form>
	
</div> <!-- .wrap -->

Agora estamos verificando as propriedades $this->login_error para ver se existe algum erro no login, e $this->logged_in, para saber se o usuário está logado.

O formulário acima deverá exibir uma mensagem caso a senha do usuário estiver incorreta, se o usuário não existir, se ele está logado e coisas do tipo.

Formulário de login

Formulário de login

As mensagens estão em inglês porque a classe UserLogin era de outro sistema que eu havia criado anteriormente. Você pode alterar conforme preferir.

Criando o controller para registro de usuários

O controle de usuários é essencial para nossa aplicação, sem ele não poderíamos bloquear ou permitir nada.

Este controller só irá permitir que o view seja acessado por usuários logados. Além disso, ele também só irá permitir que um usuário visualize seu conteúdo se o mesmo tiver a permissão necessária.

Como funcionam as permissões?

Na verdade, você é quem escolhe como funcionam as permissões.

O formulário de cadastro terá um campo onde você separa as permissões por vírgula, por exemplo:

  • acessar-home, gerenciar-noticias, abrir-modelo-adm, e assim por diante…

Em seguida, é só verificar no controller se o usuário tem aquela permissão, por exemplo:

// Verifica se o usuário tem a permissão para acessar essa página
if (!$this->check_permissions('permissao-necessaria', $this->userdata['user_permissions'])) {

	// Exibe uma mensagem
	echo 'Você não tem permissões para acessar essa página.';
	
	// Finaliza aqui
	return;
}

Simples assim!

controllers/user-register-controller.php

Vejamos agora o código do nosso controller para registro de usuários:

<?php
/**
 * UserRegisterController - Controller de exemplo
 *
 * @package TutsupMVC
 * @since 0.1
 */
class UserRegisterController extends MainController
{

   /**
    * $login_required
    *
    * Se a página precisa de login
    *
    * @access public
    */
    public $login_required = true;

    /**
     * $permission_required
     *
     * Permissão necessária
     *
     * @access public
     */
    public $permission_required = 'user-register';

    /**
     * Carrega a página "/views/user-register/index.php"
     */
    public function index() {
		// Page title
		$this->title = 'User Register';
		
		// Verifica se o usuário está logado
		if ( ! $this->logged_in ) {
		
			// Se não; garante o logout
			$this->logout();
			
			// Redireciona para a página de login
			$this->goto_login();
			
			// Garante que o script não vai passar daqui
			return;
		
		}
		
		// Verifica se o usuário tem a permissão para acessar essa página
		if (!$this->check_permissions($this->permission_required, $this->userdata['user_permissions'])) {
		
			// Exibe uma mensagem
			echo 'Você não tem permissões para acessar essa página.';
			
			// Finaliza aqui
			return;
		}
	
		// Parametros da função
		$parametros = ( func_num_args() >= 1 ) ? func_get_arg(0) : array();
	
	// Carrega o modelo para este view
        $modelo = $this->load_model('user-register/user-register-model');
				
	/** Carrega os arquivos do view **/
		
	// /views/_includes/header.php
        require ABSPATH . '/views/_includes/header.php';
		
	// /views/_includes/menu.php
        require ABSPATH . '/views/_includes/menu.php';
		
	// /views/user-register/index.php
        require ABSPATH . '/views/user-register/user-register-view.php';
		
	// /views/_includes/footer.php
        require ABSPATH . '/views/_includes/footer.php';
		
    } // index
	
} // class UserRegisterController

Este controle verifica se o usuário está logado e se ele tem permissões para acessar tal página, veja o trecho:

public $permission_required = 'user-register';

/* ... */
		
// Verifica se o usuário está logado
if ( ! $this->logged_in ) {
	
	// Se não; garante o logout
	$this->logout();
	
	// Redireciona para a página de login
	$this->goto_login();
			
	// Garante que o script não vai passar daqui
	return;
		
}
		
// Verifica se o usuário tem a permissão para acessar essa página
if (!$this->check_permissions($this->permission_required, $this->userdata['user_permissions'])) {
	
	// Exibe uma mensagem
	echo 'Você não tem permissões para acessar essa página.';
		
	// Finaliza aqui
	return;
}

Depois dessa verificação, incluímos o model e os views.

Criando o model para registro de usuários

Vamos analisar o código do model.

models/user-register/user-register-model.php

Este é um modelo bem grande, pois já inclui todo o sistema de CRUD (create, read, update and delete). Mas não se assuste com o tamanho, pois ele fará praticamente a mesma coisa que todos os seus modelos irão fazer:

<?php 
/**
 * Classe para registros de usuários
 *
 * @package TutsupMVC
 * @since 0.1
 */

class UserRegisterModel
{

	/**
	 * $form_data
	 *
	 * Os dados do formulário de envio.
	 *
	 * @access public
	 */	
	public $form_data;

	/**
	 * $form_msg
	 *
	 * As mensagens de feedback para o usuário.
	 *
	 * @access public
	 */	
	public $form_msg;

	/**
	 * $db
	 *
	 * O objeto da nossa conexão PDO
	 *
	 * @access public
	 */
	public $db;

	/**
	 * Construtor
	 * 
	 * Carrega  o DB.
	 *
	 * @since 0.1
	 * @access public
	 */
	public function __construct( $db = false ) {
                // Carrega o BD
		$this->db = $db;
	}

	/**
	 * Valida o formulário de envio
	 * 
	 * Este método pode inserir ou atualizar dados dependendo do campo de
	 * usuário.
	 *
	 * @since 0.1
	 * @access public
	 */
	public function validate_register_form () {
	
		// Configura os dados do formulário
		$this->form_data = array();
		
		// Verifica se algo foi postado
		if ( 'POST' == $_SERVER['REQUEST_METHOD'] && ! empty ( $_POST ) ) {
		
			// Faz o loop dos dados do post
			foreach ( $_POST as $key => $value ) {
			
				// Configura os dados do post para a propriedade $form_data
				$this->form_data[$key] = $value;
				
				// Nós não permitiremos nenhum campos em branco
				if ( empty( $value ) ) {
					
					// Configura a mensagem
					$this->form_msg = '<p class="form_error">There are empty fields. Data has not been sent.</p>';
					
					// Termina
					return;
					
				}			
			
			}
		
		} else {
		
			// Termina se nada foi enviado
			return;
			
		}
		
		// Verifica se a propriedade $form_data foi preenchida
		if( empty( $this->form_data ) ) {
			return;
		}
		
		// Verifica se o usuário existe
		$db_check_user = $this->db->query (
			'SELECT * FROM `users` WHERE `user` = ?', 
			array( 
				chk_array( $this->form_data, 'user')		
			) 
		);
		
		// Verifica se a consulta foi realizada com sucesso
		if ( ! $db_check_user ) {
			$this->form_msg = '<p class="form_error">Internal error.</p>';
			return;
		}
		
		// Obtém os dados da base de dados MySQL
		$fetch_user = $db_check_user->fetch();
		
		// Configura o ID do usuário
		$user_id = $fetch_user['user_id'];
		
		// Precisaremos de uma instância da classe Phpass
		// veja http://www.openwall.com/phpass/
		$password_hash = new PasswordHash(8, FALSE);
		
		// Cria o hash da senha
		$password = $password_hash->HashPassword( $this->form_data['user_password'] );
		
		// Verifica se as permissões tem algum valor inválido: 
		// 0 a 9, A a Z e , . - _
		if ( preg_match( '/[^0-9A-Za-z,.-_s ]/is', $this->form_data['user_permissions'] ) ) {
			$this->form_msg = '<p class="form_error">Use just letters, numbers and a comma for permissions.</p>';
			return;
		}		
		
		// Faz um trim nas permissões
		$permissions = array_map('trim', explode(',', $this->form_data['user_permissions']));
		
		// Remove permissões duplicadas
		$permissions = array_unique( $permissions );
		
		// Remove valores em branco
		$permissions = array_filter( $permissions );
		
		// Serializa as permissões
		$permissions = serialize( $permissions );
		
		
		// Se o ID do usuário não estiver vazio, atualiza os dados
		if ( ! empty( $user_id ) ) {

			$query = $this->db->update('users', 'user_id', $user_id, array(
				'user_password' => $password, 
				'user_name' => chk_array( $this->form_data, 'user_name'), 
				'user_session_id' => md5(time()), 
				'user_permissions' => $permissions, 
			));
			
			// Verifica se a consulta está OK e configura a mensagem
			if ( ! $query ) {
				$this->form_msg = '<p class="form_error">Internal error. Data has not been sent.</p>';
				
				// Termina
				return;
			} else {
				$this->form_msg = '<p class="form_success">User successfully updated.</p>';
				
				// Termina
				return;
			}
		// Se o ID do usuário estiver vazio, insere os dados
		} else {
		
			// Executa a consulta 
			$query = $this->db->insert('users', array(
				'user' => chk_array( $this->form_data, 'user'), 
				'user_password' => $password, 
				'user_name' => chk_array( $this->form_data, 'user_name'), 
				'user_session_id' => md5(time()), 
				'user_permissions' => $permissions, 
			));
			
			// Verifica se a consulta está OK e configura a mensagem
			if ( ! $query ) {
				$this->form_msg = '<p class="form_error">Internal error. Data has not been sent.</p>';
				
				// Termina
				return;
			} else {
				$this->form_msg = '<p class="form_success">User successfully registered.</p>';
				
				// Termina
				return;
			}
		}
	} // validate_register_form
	
	/**
	 * Obtém os dados do formulário
	 * 
	 * Obtém os dados para usuários registrados
	 *
	 * @since 0.1
	 * @access public
	 */
	public function get_register_form ( $user_id = false ) {
	
		// O ID de usuário que vamos pesquisar
		$s_user_id = false;
		
		// Verifica se você enviou algum ID para o método
		if ( ! empty( $user_id ) ) {
			$s_user_id = (int)$user_id;
		}
		
		// Verifica se existe um ID de usuário
		if ( empty( $s_user_id ) ) {
			return;
		}
		
		// Verifica na base de dados
		$query = $this->db->query('SELECT * FROM `users` WHERE `user_id` = ?', array( $s_user_id ));
		
		// Verifica a consulta
		if ( ! $query ) {
			$this->form_msg = '<p class="form_error">Usuário não existe.</p>';
			return;
		}
		
		// Obtém os dados da consulta
		$fetch_userdata = $query->fetch();
		
		// Verifica se os dados da consulta estão vazios
		if ( empty( $fetch_userdata ) ) {
			$this->form_msg = '<p class="form_error">User do not exists.</p>';
			return;
		}
		
		// Configura os dados do formulário
		foreach ( $fetch_userdata as $key => $value ) {
			$this->form_data[$key] = $value;
		}
		
		// Por questões de segurança, a senha só poderá ser atualizada
		$this->form_data['user_password'] = null;
		
		// Remove a serialização das permissões
		$this->form_data['user_permissions'] = unserialize($this->form_data['user_permissions']);
		
		// Separa as permissões por vírgula
		$this->form_data['user_permissions'] = implode(',', $this->form_data['user_permissions']);
	} // get_register_form
	
	/**
	 * Apaga usuários
	 * 
	 * @since 0.1
	 * @access public
	 */
	public function del_user ( $parametros = array() ) {

		// O ID do usuário
		$user_id = null;
		
		// Verifica se existe o parâmetro "del" na URL
		if ( chk_array( $parametros, 0 ) == 'del' ) {

			// Mostra uma mensagem de confirmação
			echo '<p class="alert">Tem certeza que deseja apagar este valor?</p>';
			echo '<p><a href="' . $_SERVER['REQUEST_URI'] . '/confirma">Sim</a> | 
			<a href="' . HOME_URI . '/user-register">Não</a> </p>';
			
			// Verifica se o valor do parâmetro é um número
			if ( 
				is_numeric( chk_array( $parametros, 1 ) )
				&& chk_array( $parametros, 2 ) == 'confirma' 
			) {
				// Configura o ID do usuário a ser apagado
				$user_id = chk_array( $parametros, 1 );
			}
		}
		
		// Verifica se o ID não está vazio
		if ( !empty( $user_id ) ) {
		
			// O ID precisa ser inteiro
			$user_id = (int)$user_id;
			
			// Deleta o usuário
			$query = $this->db->delete('users', 'user_id', $user_id);
			
			// Redireciona para a página de registros
			echo '<meta http-equiv="Refresh" content="0; url=' . HOME_URI . '/user-register/">';
			echo '<script type="text/javascript">window.location.href = "' . HOME_URI . '/user-register/";</script>';
			return;
		}
	} // del_user
	
	/**
	 * Obtém a lista de usuários
	 * 
	 * @since 0.1
	 * @access public
	 */
	public function get_user_list() {
	
		// Simplesmente seleciona os dados na base de dados 
		$query = $this->db->query('SELECT * FROM `users` ORDER BY user_id DESC');
		
		// Verifica se a consulta está OK
		if ( ! $query ) {
			return array();
		}
		// Preenche a tabela com os dados do usuário
		return $query->fetchAll();
	} // get_user_list
}

Como eu disse, isso é o que estamos acostumados a fazer com aplicações. Conectamos à base de dados e gerenciamos os dados.

É importante lembrar, que tudo o que está descrito no model acima, será acionado pelo view.

Por falar em view, vamos analisar como ele irá funcionar.

Criando um view para registro de usuários

O view é simplesmente um formulário HTML, mas também vamos executar as ações do model que precisamos, veja seu código:

views/user-register/user-register-view.php

<?php if ( ! defined('ABSPATH')) exit; ?>

<div class="wrap">

<?php
// Carrega todos os métodos do modelo
$modelo->validate_register_form();
$modelo->get_register_form( chk_array( $parametros, 1 ) );
$modelo->del_user( $parametros );
?>

<form method="post" action="">
	<table class="form-table">
		<tr>
			<td>Name: </td>
			<td> <input type="text" name="user_name" value="<?php 
				echo htmlentities( chk_array( $modelo->form_data, 'user_name') );
				?>" /></td>
		</tr>
		<tr>
			<td>User: </td>
			<td> <input type="text" name="user" value="<?php
				echo htmlentities( chk_array( $modelo->form_data, 'user') );
			?>" /></td>
		</tr>
		<tr>
			<td>Password: </td>
			<td> <input type="password" name="user_password" value="<?php
			echo htmlentities( chk_array( $modelo->form_data, 'user_password') );
			?>" /></td>
		</tr>
		<tr>
			<td>Permissions <br><small>(Separate permissions using commas)</small>: </td>
			<td> <input type="text" name="user_permissions" value="<?php
			echo htmlentities( chk_array( $modelo->form_data, 'user_permissions') );
			?>" /></td>
		</tr>
		<tr>
			<td colspan="2">
				<?php echo $modelo->form_msg;?>
				<input type="submit" value="Save" />
				<a href="<?php echo HOME_URI . '/user-register';?>">New user</a>
			</td>
		</tr>
	</table>
</form>

<?php 
// Lista os usuários
$lista = $modelo->get_user_list(); 
?>


<table class="list-table">
	<thead>
		<tr>
			<th>ID</th>
			<th>Usuário</th>
			<th>Name</th>
			<th>Permissões</th>
			<th>Edição</th>
		</tr>
	</thead>
			
	<tbody>
			
		<?php foreach ($lista as $fetch_userdata): ?>

			<tr>
			
				<td> <?php echo $fetch_userdata['user_id'] ?> </td>
				<td> <?php echo $fetch_userdata['user'] ?> </td>
				<td> <?php echo $fetch_userdata['user_name'] ?> </td>
				<td> <?php echo implode( ',', unserialize( $fetch_userdata['user_permissions'] ) ) ?> </td>
				
				<td> 
					<a href="<?php echo HOME_URI ?>/user-register/index/edit/<?php echo $fetch_userdata['user_id'] ?>">Edit</a>
					<a href="<?php echo HOME_URI ?>/user-register/index/del/<?php echo $fetch_userdata['user_id'] ?>">Delete</a>
				</td>

			</tr>
			
		<?php endforeach;?>
			
	</tbody>
</table>

</div> <!-- .wrap -->

Acessamos as ações que queremos do nosso model através da variável $modelo, criada no nosso controller.

Apenas com este view, temos a capacidade de criar, apagar, editar e visualizar todos os usuários.

Lembre-se que utilizamos um hash de senha bem seguro, portanto, não podemos obter os dados de senha dos usuários, somente modificar a mesma.

Formulário de registro

Formulário de registro

Download

Como estamos criando uma aplicação inteira, são vários arquivos que se encaixam uns nos outros. Se você quiser baixar os dados e ir acompanhando com eles em seu computador, segue o link abaixo:

Caso queira contribuir com o projeto, acesso no Github:

No download acima, a aplicação está praticamente completa. Pode ser que algo seja alterado conforme nossa necessidade, mas vou detalhar tudo no artigo.

Outras partes do artigo

Este artigo está dividido em várias partes, pois seu conteúdo é muito extenso. Também existe uma categoria exclusiva para todo seu conteúdo, chamada de MVC em PHP.

Veja todas as suas partes já publicas nos links abaixo:

Em caso de dúvidas, comente-a!

 

Outra parte muito importante da nossa aplicação com estrutura MVC em PHP é a base de dados. A maioria dos sistemas que iremos criar terá acesso ao banco de dados, tanto para salvar dados relevantes como para manipular os dados de usuários.

Para nosso tutorial, criei uma classe que gerencia tudo o que é relacionado à base de dados, como conexão e manipulação de dados.

A classe responsável por manter a base de dados é a “TutsupDB”, que está na pasta “classes”, com o nome “class-TutsupDB.php”.

Mais adiante neste artigo vamos analisar seu código, bem como demais classes que formam nosso formato de MVC em PHP.

Download

Como estamos criando uma aplicação inteira, são vários arquivos que se encaixam uns nos outros. Se você quiser baixar os dados e ir acompanhando com eles em seu computador, segue o link abaixo:

Caso queira contribuir com o projeto, acesso no Github:

No download acima, a aplicação está praticamente completa. Pode ser que algo seja alterado conforme nossa necessidade, mas vou detalhar tudo no artigo.

classes/class-TutsupDB.php

A classe TutsupDB faz a conexão PDO e gerencia dados da base de dados, veja seu código:

<?php
/**
 * TutsupDB - Classe para gerenciamento da base de dados
 *
 * @package TutsupMVC
 * @since 0.1
 */
class TutsupDB
{
	/** DB properties */
	public $host      = 'localhost', // Host da base de dados 
	       $db_name   = 'tutsup',    // Nome do banco de dados
	       $password  = '',          // Senha do usuário da base de dados
	       $user      = 'root',      // Usuário da base de dados
	       $charset   = 'utf8',      // Charset da base de dados
	       $pdo       = null,        // Nossa conexão com o BD
	       $error     = null,        // Configura o erro
	       $debug     = false,       // Mostra todos os erros 
	       $last_id   = null;        // Último ID inserido
	
	/**
	 * Construtor da classe
	 *
	 * @since 0.1
	 * @access public
	 * @param string $host     
	 * @param string $db_name
	 * @param string $password
	 * @param string $user
	 * @param string $charset
	 * @param string $debug
	 */
	public function __construct(
		$host     = null,
		$db_name  = null,
		$password = null,
		$user     = null,
		$charset  = null,
		$debug    = null
	) {
	
		// Configura as propriedades novamente.
		// Se você fez isso no início dessa classe, as constantes não serão
		// necessárias. Você escolhe...
		$this->host     = defined( 'HOSTNAME'    ) ? HOSTNAME    : $this->host;
		$this->db_name  = defined( 'DB_NAME'     ) ? DB_NAME     : $this->db_name;
		$this->password = defined( 'DB_PASSWORD' ) ? DB_PASSWORD : $this->password;
		$this->user     = defined( 'DB_USER'     ) ? DB_USER     : $this->user;
		$this->charset  = defined( 'DB_CHARSET'  ) ? DB_CHARSET  : $this->charset;
		$this->debug    = defined( 'DEBUG'       ) ? DEBUG       : $this->debug;
	
		// Conecta
		$this->connect();
		
	} // __construct
	
	/**
	 * Cria a conexão PDO
	 *
	 * @since 0.1
	 * @final
	 * @access protected
	 */
	final protected function connect() {
	
		/* Os detalhes da nossa conexão PDO */
		$pdo_details  = "mysql:host={$this->host};";
		$pdo_details .= "dbname={$this->db_name};";
		$pdo_details .= "charset={$this->charset};";
		 
		// Tenta conectar
		try {
		
			$this->pdo = new PDO($pdo_details, $this->user, $this->password);
			
			// Verifica se devemos debugar
			if ( $this->debug === true ) {
			
				// Configura o PDO ERROR MODE
				$this->pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
				
			}
			
			// Não precisamos mais dessas propriedades
			unset( $this->host     );
			unset( $this->db_name  );
			unset( $this->password );
			unset( $this->user     );
			unset( $this->charset  );
		
		} catch (PDOException $e) {
			
			// Verifica se devemos debugar
			if ( $this->debug === true ) {
			
				// Mostra a mensagem de erro
				echo "Erro: " . $e->getMessage();
				
			}
			
			// Kills the script
			die();
		} // catch
	} // connect
	
	/**
	 * query - Consulta PDO
	 *
	 * @since 0.1
	 * @access public
	 * @return object|bool Retorna a consulta ou falso
	 */
	public function query( $stmt, $data_array = null ) {
		
		// Prepara e executa
		$query      = $this->pdo->prepare( $stmt );
		$check_exec = $query->execute( $data_array );
		
		// Verifica se a consulta aconteceu
		if ( $check_exec ) {
			
			// Retorna a consulta
			return $query;
			
		} else {
		
			// Configura o erro
			$error       = $query->errorInfo();
			$this->error = $error[2];
			
			// Retorna falso
			return false;
			
		}
	}
	
	/**
	 * insert - Insere valores
	 *
	 * Insere os valores e tenta retornar o último id enviado
	 *
	 * @since 0.1
	 * @access public
	 * @param string $table O nome da tabela
	 * @param array ... Ilimitado número de arrays com chaves e valores
	 * @return object|bool Retorna a consulta ou falso
	 */
	public function insert( $table ) {
		// Configura o array de colunas
		$cols = array();
		
		// Configura o valor inicial do modelo
		$place_holders = '(';
		
		// Configura o array de valores
		$values = array();
		
		// O $j will assegura que colunas serão configuradas apenas uma vez
		$j = 1;
		
		// Obtém os argumentos enviados
		$data = func_get_args();
		
		// É preciso enviar pelo menos um array de chaves e valores
		if ( ! isset( $data[1] ) || ! is_array( $data[1] ) ) {
			return;
		}
		
		// Faz um laço nos argumentos
		for ( $i = 1; $i < count( $data ); $i++ ) {
		
			// Obtém as chaves como colunas e valores como valores
			foreach ( $data[$i] as $col => $val ) {
			
				// A primeira volta do laço configura as colunas
				if ( $i === 1 ) {
					$cols[] = "`$col`";
				}
				
				if ( $j <> $i ) {
					// Configura os divisores
					$place_holders .= '), (';
				}
				
				// Configura os place holders do PDO
				$place_holders .= '?, ';
				
				// Configura os valores que vamos enviar
				$values[] = $val;
				
				$j = $i;
			}
			
			// Remove os caracteres extra dos place holders
			$place_holders = substr( $place_holders, 0, strlen( $place_holders ) - 2 );
		}
		
		// Separa as colunas por vírgula
		$cols = implode(', ', $cols);
		
		// Cria a declaração para enviar ao PDO
		$stmt = "INSERT INTO `$table` ( $cols ) VALUES $place_holders) ";
		
		// Insere os valores
		$insert = $this->query( $stmt, $values );
		
		// Verifica se a consulta foi realizada com sucesso
		if ( $insert ) {
			
			// Verifica se temos o último ID enviado
			if ( method_exists( $this->pdo, 'lastInsertId' ) 
				&& $this->pdo->lastInsertId() 
			) {
				// Configura o último ID
				$this->last_id = $this->pdo->lastInsertId();
			}
			
			// Retorna a consulta
			return $insert;
		}
		
		// The end :)
		return;
	} // insert
	
	/**
	 * Update simples
	 *
	 * Atualiza uma linha da tabela baseada em um campo
	 *
	 * @since 0.1
	 * @access protected
	 * @param string $table Nome da tabela
	 * @param string $where_field WHERE $where_field = $where_field_value
	 * @param string $where_field_value WHERE $where_field = $where_field_value
	 * @param array $values Um array com os novos valores
	 * @return object|bool Retorna a consulta ou falso
	 */
	public function update( $table, $where_field, $where_field_value, $values ) {
		// Você tem que enviar todos os parâmetros
		if ( empty($table) || empty($where_field) || empty($where_field_value)  ) {
			return;
		}
		
		// Começa a declaração
		$stmt = " UPDATE `$table` SET ";
		
		// Configura o array de valores
		$set = array();
		
		// Configura a declaração do WHERE campo=valor
		$where = " WHERE `$where_field` = ? ";
		
		// Você precisa enviar um array com valores
		if ( ! is_array( $values ) ) {
			return;
		}
		
		// Configura as colunas a atualizar
		foreach ( $values as $column => $value ) {
			$set[] = " `$column` = ?";
		}
		
		// Separa as colunas por vírgula
		$set = implode(', ', $set);
		
		// Concatena a declaração
		$stmt .= $set . $where;
		
		// Configura o valor do campo que vamos buscar
		$values[] = $where_field_value;
		
		// Garante apenas números nas chaves do array
		$values = array_values($values);
				
		// Atualiza
		$update = $this->query( $stmt, $values );
		
		// Verifica se a consulta está OK
		if ( $update ) {
			// Retorna a consulta
			return $update;
		}
		
		// The end :)
		return;
	} // update

	/**
	 * Delete
	 *
	 * Deleta uma linha da tabela
	 *
	 * @since 0.1
	 * @access protected
	 * @param string $table Nome da tabela
	 * @param string $where_field WHERE $where_field = $where_field_value
	 * @param string $where_field_value WHERE $where_field = $where_field_value
	 * @return object|bool Retorna a consulta ou falso
	 */
	public function delete( $table, $where_field, $where_field_value ) {
		// Você precisa enviar todos os parâmetros
		if ( empty($table) || empty($where_field) || empty($where_field_value)  ) {
			return;
		}
		
		// Inicia a declaração
		$stmt = " DELETE FROM `$table` ";

		// Configura a declaração WHERE campo=valor
		$where = " WHERE `$where_field` = ? ";
		
		// Concatena tudo
		$stmt .= $where;
		
		// O valor que vamos buscar para apagar
		$values = array( $where_field_value );

		// Apaga
		$delete = $this->query( $stmt, $values );
		
		// Verifica se a consulta está OK
		if ( $delete ) {
			// Retorna a consulta
			return $delete;
		}
		
		// The end :)
		return;
	} // delete
	
} // Class TutsupDB

Ela utiliza os dados das constantes presentes no arquivo config.php para realizar a conexão com a base de dados.

Os exemplos de utilização seriam mais ou menos assim:

<?php
// Objeto
$db = new TutsupDB();

// Insere
$db->insert(
	'tabela', 
	
	// Insere uma linha
	array('campo_tabela' => 'valor', 'outro_campo'  => 'outro_valor'),
	
	// Insere outra linha
	array('campo_tabela' => 'valor', 'outro_campo'  => 'outro_valor'),
	
	// Insere outra linha
	array('campo_tabela' => 'valor', 'outro_campo'  => 'outro_valor')
);

// Atualiza
$db->update(
	'tabela', 'campo_where', 'valor_where',
	
	// Atualiza a linha
	array('campo_tabela' => 'valor', 'outro_campo'  => 'outro_valor')
);

// Apaga
$db->delete(
	'tabela', 'campo_where', 'valor_where'
);

// Seleciona
$db->query(
	'SELECT * FROM tabela WHERE campo = ? AND outro_campo = ?',
	array( 'valor', 'valor' )
);

Como estamos inserindo os dados da conexão em uma propriedade do nosso modelo, a utilização ficaria assim:

<?php
// Objeto
$modelo->db = new TutsupDB();

// Insere
$modelo->db->insert(
	'tabela', 
	
	// Insere uma linha
	array('campo_tabela' => 'valor', 'outro_campo'  => 'outro_valor'),
	
	// Insere outra linha
	array('campo_tabela' => 'valor', 'outro_campo'  => 'outro_valor'),
	
	// Insere outra linha
	array('campo_tabela' => 'valor', 'outro_campo'  => 'outro_valor')
);

// Atualiza
$modelo->db->update(
	'tabela', 'campo_where', 'valor_where',
	
	// Atualiza a linha
	array('campo_tabela' => 'valor', 'outro_campo'  => 'outro_valor')
);

// Apaga
$modelo->db->delete(
	'tabela', 'campo_where', 'valor_where'
);

// Seleciona
$modelo->db->query(
	'SELECT * FROM tabela WHERE campo = ? AND outro_campo = ?',
	array( 'valor', 'valor' )
);

Vamos analisar agora nossa classe de modelo MainModel.

classes/class-MainModel.php

Essa classe servirá para manter os métodos que poderão ser utilizados em todos os modelos, ou seja, ela o ajuda a manter a reutilização de código sempre ativa. Ela não tem muitos métodos, já que eles vão depender da sua aplicação.

Adicionei um método simples nela apenas para inverter a data das notícias que iremos cadastrar.

Uma parte importante da classe MainModel, é que ela mantém muitas propriedades que utilizamos constantemente em nossos views e models, portanto, todos os outros modelos deverão estender essa classe.

Veja seu código:

<?php
/**
 * MainModel - Modelo geral
 *
 * 
 *
 * @package TutsupMVC
 * @since 0.1
 */
class MainModel
{
	/**
	 * $form_data
	 *
	 * Os dados de formulários de envio.
	 *
	 * @access public
	 */	
	public $form_data;

	/**
	 * $form_msg
	 *
	 * As mensagens de feedback para formulários.
	 *
	 * @access public
	 */	
	public $form_msg;

	/**
	 * $form_confirma
	 *
	 * Mensagem de confirmação para apagar dados de formulários
	 *
	 * @access public
	 */
	public $form_confirma;

	/**
	 * $db
	 *
	 * O objeto da nossa conexão PDO
	 *
	 * @access public
	 */
	public $db;

	/**
	 * $controller
	 *
	 * O controller que gerou esse modelo
	 *
	 * @access public
	 */
	public $controller;

	/**
	 * $parametros
	 *
	 * Parâmetros da URL
	 *
	 * @access public
	 */
	public $parametros;

	/**
	 * $userdata
	 *
	 * Dados do usuário
	 *
	 * @access public
	 */
	public $userdata;
	
	/**
	 * Inverte datas 
	 *
	 * Obtém a data e inverte seu valor.
	 * De: d-m-Y H:i:s para Y-m-d H:i:s ou vice-versa.
	 *
	 * @since 0.1
	 * @access public
	 * @param string $data A data
	 */
	public function inverte_data( $data = null ) {
	
		// Configura uma variável para receber a nova data
		$nova_data = null;
		
		// Se a data for enviada
		if ( $data ) {
		
			// Explode a data por -, /, : ou espaço
			$data = preg_split('/-|/|s|:/', $data);
			
			// Remove os espaços do começo e do fim dos valores
			$data = array_map( 'trim', $data );
			
			// Cria a data invertida
			$nova_data .= chk_array( $data, 2 ) . '-';
			$nova_data .= chk_array( $data, 1 ) . '-';
			$nova_data .= chk_array( $data, 0 );
			
			// Configura a hora
			if ( chk_array( $data, 3 ) ) {
				$nova_data .= ' ' . chk_array( $data, 3 );
			}
			
			// Configura os minutos
			if ( chk_array( $data, 4 ) ) {
				$nova_data .= ':' . chk_array( $data, 4 );
			}
			
			// Configura os segundos
			if ( chk_array( $data, 5 ) ) {
				$nova_data .= ':' . chk_array( $data, 5 );
			}
		}
		
		// Retorna a nova data
		return $nova_data;
	
	} // inverte_data

} // MainModel

Conforme descrevi, ela não tem muita coisa, apenas algo que seja necessário para vários modelos.

Criando meu primeiro MVC – Model – Controller – View

Agora que já falamos das partes mais importantes do nosso modelo, vamos criar nosso primeiro MVC em PHP.

Nas verdade a ordem correta para a nossa descrição seria CMV (apenas exemplo), já que essa é a ordem que nosso programa procura os arquivos.

Criando um controller

Os controllers devem ser inseridos na pasta “controllers” com o seguinte formato de nome:

  • exemplo-controller.php

Onde “exemplo” é o nome do seu controller. O final -controller.php é obrigatório.

Tive que fazer isso, porque eu me perdia facilmente no nome dos arquivos quando estava desenvolvendo.

Isso acontece apenas com os controladores, mas para facilitar minha vida resolvi adaptar o mesmo modelo para tudo, models, controllers e views (você vai perceber isso posteriormente no artigo).

Apenas para nosso exemplo, crie um arquivo chamado “exemplo-controller.php” e vamos adicionar uma classe com o mesmo nome do arquivo, porém sem nenhum traço.

Veja:

<?php
class ExemploController extends MainController
{
   // Aqui vem nossas ações
}

Observação: A classe deverá ter o mesmo nome do arquivo (incluindo a palavra controller).

Apenas criando a nossa classe não fará a aplicação funcionar, temos que ter pelo menos uma ação (método), veja:

<?php
class ExemploController extends MainController
{
	// URL: dominio.com/exemplo/
	public function index() {
	
		// Carrega o modelo
		$modelo = $this->load_model('exemplo/exemplo-model');
		
		// Carrega o view
		require_once ABSPATH . '/views/exemplo/exemplo-view.php';
	}
}

Veja que criamos uma ação chamada index. Essa ação carrega o modelo e view que precisaremos.

Você pode optar por não utilizar um model, apenas o view, isso fica a seu critério.

Vamos ver os arquivos de model e view.

Criando um model

Os modelos ficam dentro da pasta “models”.

Apenas por convenção de nomes, sempre crio meus modelos com o seguinte formato:

  • modelo-model.php

Sempre com o mesmo nome do seu controller.

Para nosso exemplo, meu modelo ficou com o seguinte note:

  • exemplo-model.php

Outra coisa que faço para deixar a estrutura de arquivos mais organizada é separar os modelos por pastas. Para todos os modelos de “exemplo“, crio uma pasta exemplo e salvo tudo que é referente a exemplos lá dentro.

Crie um arquivo chamado “exemplo-model.php” dentro da pasta “exemplo” (que será criada dentro da pasta models) e vamos configurar o código deste arquivo.

<?php
class ExemploModel extends MainModel
{
	/**
	 * Construtor para essa classe
	 *
	 * Configura o DB, o controlador, os parâmetros e dados do usuário.
	 *
	 * @since 0.1
	 * @access public
	 * @param object $db Objeto da nossa conexão PDO
	 * @param object $controller Objeto do controlador
	 */
	public function __construct( $db = false, $controller = null ) {
		// Configura o DB (PDO)
		$this->db = $db;
		
		// Configura o controlador
		$this->controller = $controller;

		// Configura os parâmetros
		$this->parametros = $this->controller->parametros;

		// Configura os dados do usuário
		$this->userdata = $this->controller->userdata;
		
		echo 'Modelo carregado... <br>';
	}
	
	// Crie seus próprios métodos daqui em diante
}

Perceba que meu modelo de exemplo é uma classe com o mesmo nome do arquivo (sem caracteres especiais).

Por exemplo, para o arquivo compras-model.php, sua classe deverá se chamar ComprasModel.

No construtor da nossa classe, configuramos todas as variáveis que vamos precisar, como base de dados, dados de usuário e assim por diante.

Nosso controlador vai enviar seu objeto para o seu modelo no segundo parâmetro, você poderá utilizar todos os métodos já criados anteriormente utilizando tal objeto.

Vamos criar nosso view e exibir os dados desse modelo.

Criando um view

Agora que já temos um controlador e um modelo, precisamos de um view para exibir os dados.

Os views ficam na pasta views. Normalmente separados em suas próprias pastas.

Crie uma pasta chamada “exemplo“, e um arquivo chamado “exemplo-view.php“.

Neste arquivo você terá todas as propriedades e métodos do controlador e do modelo, veja:

<?php
echo '<h2>Dados do modelo.</h2>';
echo '<pre>';
print_r( $modelo );
echo '</pre>';
?>

<h2>Pronto</h2>

<p>Inclua seu site ou dados neste view...</p>

Isso deverá gerar o seguinte na tela:

Exemplo

Exemplo

Faça o download e o teste. Veja se tudo corre conforme descrito.

Download

Caso queira baixar os arquivos para testes ou utilização, segue abaixo:

Caso queira contribuir com o projeto, acesso no Github:

No download acima, a aplicação está praticamente completa. Pode ser que algo seja alterado conforme nossa necessidade, mas vou detalhar tudo no artigo.

Outras partes do artigo

Este artigo está dividido em várias partes, pois seu conteúdo é muito extenso. Também existe uma categoria exclusiva para todo seu conteúdo, chamada de MVC em PHP.

Veja todas as suas partes já publicas nos links abaixo:

Em caso de dúvidas, comente-a!

 

 

Continuando com o desenvolvimento da nossa aplicação com estrutura MVC em PHP, hoje você vai entender como funciona a classe TutsupMVC, que está presente na pasta classes, em um arquivo chamado class-TutsupMVC.php.

É uma classe relativamente pequena, porém muito importante. Ela carrega o controlador e executa a ação que irá incluir o model e view, formando assim a estrutura MVC. Se ela não funcionar corretamente, toda nossa aplicação irá ter problemas, por isso é muito importante que você saiba como ela funciona.

Além disso, também vamos falar sobre todas as classes que TutsupMVC carrega, gerando um desencadeamento de classes que serão carregadas até gerar um view para o usuário.

Lembre-se que este artigo é parte de uma série de artigos sobre MVC em PHP, não deixe de ler a aula anterior:

Então vamos lá!

Como a classe TutsupMVC funciona?

Antes de vermos códigos, vamos analisar um desenho simples mostrando como a classe funciona:

 

Classe TutsupMVC e o fluxo da informação

Classe TutsupMVC e o fluxo da informação

Na imagem acima, as classes que estão em amarelo são parte da estrutura. A classe TutsupMVC desencadeia uma série de outras classes que fazem parte de um quebra-cabeça para fazer a aplicação funcionar conforme pretendemos.

O controlador personalizado terá todos os métodos e propriedades presentes em todas essas classes, bem como as funcionalidades, como verificação se o usuário está ou não logado, permissões, conexão PDO, métodos para criar, apagar, atualizar e editar dados da base de dados, e qualquer coisa que criarmos posteriormente.

Lembra da imagem que apresentei no último artigo sobre MVC em PHP? Veja agora uma junção de ambas:

Modelo MVC em PHP

Modelo MVC em PHP

Com os modelos acima em mente, veja alguns detalhes importantes sobre as classes:

  1. TutsupMVC só vai tentar carregar seu controller se isso for especificado na URL. Por exemplo: exemplo.com/seu-controller/. Caso contrário, o controlador “home” será incluído e a ação index() será executada;
  2. Se nenhuma ação for especificada na URL (exemplo.com/seu-controller/acao/), TutsupMVC vai tentar carregar a ação index(); se a ação index() não existir, a página de erro 404.php é incluída;
  3. Seu Controller deverá estender a classe “MainController”;
  4. Seu Model deverá estender a classe “MainModel”;
  5. Seu Model estará disponível dentro do seu view por um objeto que você mesmo vai criar;

Agora vamos ver um pouco de código PHP.

classes/class-TutsupMVC.php

Então vamos ver o que realmente interessa, o código.

Caso queira baixar o que já criamos até agora para acompanhar, segue o link:

A classe encontra-se em: classes/class-TutsupMVC.php e contém o seguinte:

<?php
/**
 * TutsupMVC - Gerencia Models, Controllers e Views
 *
 * @package TutsupMVC
 * @since 0.1
 */
class TutsupMVC
{

	/**
	 * $controlador
	 *
	 * Receberá o valor do controlador (Vindo da URL).
	 * exemplo.com/controlador/
	 *
	 * @access private
	 */
	private $controlador;
	
	/**
	 * $acao
	 *
	 * Receberá o valor da ação (Também vem da URL):
	 * exemplo.com/controlador/acao
	 *
	 * @access private
	 */
	private $acao;
	
	/**
	 * $parametros
	 *
	 * Receberá um array dos parâmetros (Também vem da URL):
	 * exemplo.com/controlador/acao/param1/param2/param50
	 *
	 * @access private
	 */
	private $parametros;
	
	/**
	 * $not_found
	 *
	 * Caminho da página não encontrada
	 *
	 * @access private
	 */
	private $not_found = '/includes/404.php';
	
	/**
	 * Construtor para essa classe
	 *
	 * Obtém os valores do controlador, ação e parâmetros. Configura 
	 * o controlado e a ação (método).
	 */
	public function __construct () {
		
		// Obtém os valores do controlador, ação e parâmetros da URL.
		// E configura as propriedades da classe.
		$this->get_url_data();
		
		/**
		 * Verifica se o controlador existe. Caso contrário, adiciona o
		 * controlador padrão (controllers/home-controller.php) e chama o método index().
		 */
		if ( ! $this->controlador ) {
			
			// Adiciona o controlador padrão
			require_once ABSPATH . '/controllers/home-controller.php';
			
			// Cria o objeto do controlador "home-controller.php"
			// Este controlador deverá ter uma classe chamada HomeController
			$this->controlador = new HomeController();
			
			// Executa o método index()
			$this->controlador->index();
			
			// FIM :)
			return;
		
		}
		
		// Se o arquivo do controlador não existir, não faremos nada
		if ( ! file_exists( ABSPATH . '/controllers/' . $this->controlador . '.php' ) ) {
			// Página não encontrada
			require_once ABSPATH . $this->not_found;
			
			// FIM :)
			return;
		}
		
		// Inclui o arquivo do controlador
		require_once ABSPATH . '/controllers/' . $this->controlador . '.php';
		
		// Remove caracteres inválidos do nome do controlador para gerar o nome
		// da classe. Se o arquivo chamar "news-controller.php", a classe deverá
		// se chamar NewsController.
		$this->controlador = preg_replace( '/[^a-zA-Z]/i', '', $this->controlador );
		
		// Se a classe do controlador indicado não existir, não faremos nada
		if ( ! class_exists( $this->controlador ) ) {
			// Página não encontrada
			require_once ABSPATH . $this->not_found;

			// FIM :)
			return;
		} // class_exists
		
		// Cria o objeto da classe do controlador e envia os parâmetros
		$this->controlador = new $this->controlador( $this->parametros );

		// Se o método indicado existir, executa o método e envia os parâmetros
		if ( method_exists( $this->controlador, $this->acao ) ) {
			$this->controlador->{$this->acao}( $this->parametros );
			
			// FIM :)
			return;
		} // method_exists
		
		// Sem ação, chamamos o método index
		if ( ! $this->acao && method_exists( $this->controlador, 'index' ) ) {
			$this->controlador->index( $this->parametros );		
			
			// FIM :)
			return;
		} // ! $this->acao 
		
		// Página não encontrada
		require_once ABSPATH . $this->not_found;
		
		// FIM :)
		return;
	} // __construct
	
	/**
	 * Obtém parâmetros de $_GET['path']
	 *
	 * Obtém os parâmetros de $_GET['path'] e configura as propriedades 
	 * $this->controlador, $this->acao e $this->parametros
	 *
	 * A URL deverá ter o seguinte formato:
	 * http://www.example.com/controlador/acao/parametro1/parametro2/etc...
	 */
	public function get_url_data () {
		
		// Verifica se o parâmetro path foi enviado
		if ( isset( $_GET['path'] ) ) {
	
			// Captura o valor de $_GET['path']
			$path = $_GET['path'];
			
			// Limpa os dados
                        $path = rtrim($path, '/');
                        $path = filter_var($path, FILTER_SANITIZE_URL);
            
			// Cria um array de parâmetros
			$path = explode('/', $path);
			
			// Configura as propriedades
			$this->controlador  = chk_array( $path, 0 );
			$this->controlador .= '-controller';
			$this->acao         = chk_array( $path, 1 );
			
			// Configura os parâmetros
			if ( chk_array( $path, 2 ) ) {
				unset( $path[0] );
				unset( $path[1] );
				
				// Os parâmetros sempre virão após a ação
				$this->parametros = array_values( $path );
			}
			
			
			// DEBUG
			//
			// echo $this->controlador . '<br>';
			// echo $this->acao        . '<br>';
			// echo '<pre>';
			// print_r( $this->parametros );
			// echo '</pre>';
		}
	
	} // get_url_data
	
} // class TutsupMVC

É bastante código, mas vamos ver o que cada parte faz:

  1. O construtor da classe carrega o método get_url_data;
  2. get_url_data obtém os parâmetros necessários da URL;
  3. O primeiro parâmetro é o controlador que você deverá criar. Os controladores “home”, “login”, “user-register” e “noticias” já existem e vêm embutidos no pacote que você baixou. Eles servem apenas como exemplo, já que você poderá criar seus próprios models, controllers e views; Se você não indicar nenhum controlador, a ação index() do controlador “home” será executada;
  4. O segundo parâmetro é a ação. Por ação, me refiro a um método que existe dentro do controller para carregar o(s) model(s) e view(s). Se você não indicar uma ação, a classe irá buscar a ação index() dentro do seu controlador; Se essa ação não existir, a página de erro 404 é incluída (página não encontrada). Você pode personalizar essa página conforme preferir;
  5. Do terceiro parâmetro em diante, a classe irá considerar os valores como parâmetros, e enviará os dados para o seu controlador. Você pode manipular os dados conforme preferir;
  6. Tudo isso é executado no construtor da nossa classe.

Vamos ver um exemplo do controlador “home-controller.php”, que está dentro da pasta controllers.

controllers/home-controller.php

Este é o controlador padrão que é carregado quando nenhum controller é enviado para a URL. Por padrão, ele não tem nenhum model, apenas views.

Veja seu código:

<?php
/**
 * home - Controller de exemplo
 *
 * @package TutsupMVC
 * @since 0.1
 */
class HomeController extends MainController
{

	/**
	 * Carrega a página "/views/home/home-view.php"
	 */
    public function index() {
		// Título da página
		$this->title = 'Home';
		
		// Parametros da função
		$parametros = ( func_num_args() >= 1 ) ? func_get_arg(0) : array();
	
		// Essa página não precisa de modelo (model)
		
		/** Carrega os arquivos do view **/
		
		// /views/_includes/header.php
                require ABSPATH . '/views/_includes/header.php';
		
		// /views/_includes/menu.php
                require ABSPATH . '/views/_includes/menu.php';
		
		// /views/home/home-view.php
                require ABSPATH . '/views/home/home-view.php';
		
		// /views/_includes/footer.php
                require ABSPATH . '/views/_includes/footer.php';
		
    } // index
	
} // class HomeController

Perceba que ele tem apenas uma ação (um método), chamado de index().

Este método apenas inclui os views que preciso para exibir o conteúdo na tela, como:

  • /views/_includes/header.php – Cabeçalho HTML
  • /views/_includes/menu.php – Menu HTML
  • /views/home/home-view.php – Conteúdo HTML
  • /views/_includes/footer.php – Rodapé HTML

Você também pode incluir esses arquivos diretamente no seu view, neste caso você só precisaria incluir o view padrão (home-view.php) e o restante seria feito tudo dentro desse arquivo.

Existem mais coisas que você pode configurar, por exemplo:

// Título da página
$this->title = 'Home';
		
// Parametros da função
$parametros = ( func_num_args() >= 1 ) ? func_get_arg(0) : array();

No trecho acima, estamos configurando o título da página e recebendo os parâmetros que a classe TutsupMVC nos enviou.

Ainda vamos falar sobre controllers mais avançados, com permissão de usuário, e coisas do tipo, mas vamos deixar assim por enquanto.

Como a nossa classe HomeController estende a classe MainController, vamos ver o conteúdo dessa classe.

classes/class-MainController.php

Este é nosso controller padrão, todos os outros controllers irão estender essa classe. Veja seu código:

<?php
/**
 * MainController - Todos os controllers deverão estender essa classe
 *
 * @package TutsupMVC
 * @since 0.1
 */
class MainController extends UserLogin
{

	/**
	 * $db
	 *
	 * Nossa conexão com a base de dados. Manterá o objeto PDO
	 *
	 * @access public
	 */
	public $db;

	/**
	 * $phpass
	 *
	 * Classe phpass 
	 *
	 * @see http://www.openwall.com/phpass/
	 * @access public
	 */
	public $phpass;

	/**
	 * $title
	 *
	 * Título das páginas 
	 *
	 * @access public
	 */
	public $title;

	/**
	 * $login_required
	 *
	 * Se a página precisa de login
	 *
	 * @access public
	 */
	public $login_required = false;

	/**
	 * $permission_required
	 *
	 * Permissão necessária
	 *
	 * @access public
	 */
	public $permission_required = 'any';

	/**
	 * $parametros
	 *
	 * @access public
	 */
	public $parametros = array();
	
	/**
	 * Construtor da classe
	 *
	 * Configura as propriedades e métodos da classe.
	 *
	 * @since 0.1
	 * @access public
	 */
	public function __construct ( $parametros = array() ) {
	
		// Instancia do DB
		$this->db = new TutsupDB();
		
		// Phpass
		$this->phpass = new PasswordHash(8, false);
		
		// Parâmetros
		$this->parametros = $parametros;
		
		// Verifica o login
		$this->check_userlogin();
		
	} // __construct
	
	/**
	 * Load model
	 *
	 * Carrega os modelos presentes na pasta /models/.
	 *
	 * @since 0.1
	 * @access public
	 */
	public function load_model( $model_name = false ) {
	
		// Um arquivo deverá ser enviado
		if ( ! $model_name ) return;
		
		// Garante que o nome do modelo tenha letras minúsculas
		$model_name =  strtolower( $model_name );
		
		// Inclui o arquivo
		$model_path = ABSPATH . '/models/' . $model_name . '.php';
		
		// Verifica se o arquivo existe
		if ( file_exists( $model_path ) ) {
		
			// Inclui o arquivo
			require_once $model_path;
			
			// Remove os caminhos do arquivo (se tiver algum)
			$model_name = explode('/', $model_name);
			
			// Pega só o nome final do caminho
			$model_name = end( $model_name );
			
			// Remove caracteres inválidos do nome do arquivo
			$model_name = preg_replace( '/[^a-zA-Z0-9]/is', '', $model_name );
			
			// Verifica se a classe existe
			if ( class_exists( $model_name ) ) {
			
				// Retorna um objeto da classe
				return new $model_name( $this->db, $this );
			
			}
			
			// The end :)
			return;
			
		} // load_model
		
	} // load_model

} // class MainController

Nosso controlador principal configura tudo o que precisamos em seu construtor, veja essa parte do código:

// Instancia do DB
$this->db = new TutsupDB();
		
// Phpass
$this->phpass = new PasswordHash(8, false);
		
// Parâmetros
$this->parametros = $parametros;
		
// Verifica o login
$this->check_userlogin();

Aqui configuramos nossa conexão com a base de dados, criamos o objeto da classe Phpass, configuramos os parâmetros e acionamos o método que verifica se o usuário estão ou não logado.

Além disso, temos um outro método que carrega os modelos. Vamos falar dele posteriormente.

Perceba que nossa classe MainController estende outra classe chamada de UserLogin, que é responsável por verificar tudo do usuário, como fazer login, logout, verificar se ele está logado e coisas do tipo.

Vamos ver o conteúdo da classe UserLogin.

classes/class-UserLogin.php

A classe UserLogin é responsável por tudo o que é relacionado ao usuário em si, veja:

<?php
/**
 * UserLogin - Manipula os dados de usuários
 *
 * Manipula os dados de usuários, faz login e logout, verifica permissões e 
 * redireciona página para usuários logados.
 *
 * @package TutsupMVC
 * @since 0.1
 */
class UserLogin
{
	/**
	 * Usuário logado ou não
	 *
	 * Verdadeiro se ele estiver logado.
	 *
	 * @public
	 * @access public
	 * @var bol
	 */
	public $logged_in;
	
	/**
	 * Dados do usuário
	 *
	 * @public
	 * @access public
	 * @var array
	 */
	public $userdata;
	
	/**
	 * Mensagem de erro para o formulário de login
	 *
	 * @public
	 * @access public
	 * @var string
	 */
	public $login_error;
	
	/**
	 * Verifica o login
	 *
	 * Configura as propriedades $logged_in e $login_error. Também
	 * configura o array do usuário em $userdata
	 */
	public function check_userlogin () {
	
		// Verifica se existe uma sessão com a chave userdata
		// Tem que ser um array e não pode ser HTTP POST
		if ( isset( $_SESSION['userdata'] )
			 && ! empty( $_SESSION['userdata'] )
			 && is_array( $_SESSION['userdata'] ) 
			 && ! isset( $_POST['userdata'] )
			) { 
			// Configura os dados do usuário
			$userdata = $_SESSION['userdata'];
			
			// Garante que não é HTTP POST
			$userdata['post'] = false;
		}
		
		// Verifica se existe um $_POST com a chave userdata
		// Tem que ser um array
		if ( isset( $_POST['userdata'] )
			 && ! empty( $_POST['userdata'] )
			 && is_array( $_POST['userdata'] ) 
			) {
			// Configura os dados do usuário
			$userdata = $_POST['userdata'];
			
			// Garante que é HTTP POST
			$userdata['post'] = true;
		}

		// Verifica se existe algum dado de usuário para conferir
		if ( ! isset( $userdata ) || ! is_array( $userdata ) ) {
		
			// Remove qualquer sessão que possa existir sobre o usuário
			$this->logout();
		
			return;
		}

		// Passa os dados do post para uma variável
		if ( $userdata['post'] === true ) {
			$post = true;
		} else {
			$post = false;
		}
		
		// Remove a chave post do array userdata
		unset( $userdata['post'] );
		
		// Verifica se existe algo a conferir
		if ( empty( $userdata ) ) {
			$this->logged_in = false;
			$this->login_error = null;
		
			// Remove qualquer sessão que possa existir sobre o usuário
			$this->logout();
		
			return;
		}
		
		// Extrai variáveis dos dados do usuário
		extract( $userdata );
		
		// Verifica se existe um usuário e senha
		if ( ! isset( $user ) || ! isset( $user_password ) ) {
			$this->logged_in = false;
			$this->login_error = null;
		
			// Remove qualquer sessão que possa existir sobre o usuário
			$this->logout();
		
			return;
		}
		
		// Verifica se o usuário existe na base de dados
		$query = $this->db->query( 
			'SELECT * FROM users WHERE user = ? LIMIT 1', 
			array( $user ) 
		);
		
		// Verifica a consulta
		if ( ! $query ) {
			$this->logged_in = false;
			$this->login_error = 'Internal error.';
		
			// Remove qualquer sessão que possa existir sobre o usuário
			$this->logout();
		
			return;
		}
		
		// Obtém os dados da base de usuário
		$fetch = $query->fetch(PDO::FETCH_ASSOC);
		
		// Obtém o ID do usuário
		$user_id = (int) $fetch['user_id'];
		
		// Verifica se o ID existe
		if ( empty( $user_id ) ){
			$this->logged_in = false;
			$this->login_error = 'User do not exists.';
		
			// Remove qualquer sessão que possa existir sobre o usuário
			$this->logout();
		
			return;
		}
		
		// Confere se a senha enviada pelo usuário bate com o hash do BD
		if ( $this->phpass->CheckPassword( $user_password, $fetch['user_password'] ) ) {
			
			// Se for uma sessão, verifica se a sessão bate com a sessão do BD
			if ( session_id() != $fetch['user_session_id'] && ! $post ) { 
				$this->logged_in = false;
				$this->login_error = 'Wrong session ID.';
				
				// Remove qualquer sessão que possa existir sobre o usuário
				$this->logout();
			
				return;
			}
			
			// Se for um post
			if ( $post ) {
				// Recria o ID da sessão
				session_regenerate_id();
				$session_id = session_id();
				
				// Envia os dados de usuário para a sessão
				$_SESSION['userdata'] = $fetch;
				
				// Atualiza a senha
				$_SESSION['userdata']['user_password'] = $user_password;
				
				// Atualiza o ID da sessão
				$_SESSION['userdata']['user_session_id'] = $session_id;
				
				// Atualiza o ID da sessão na base de dados
				$query = $this->db->query(
					'UPDATE users SET user_session_id = ? WHERE user_id = ?',
					array( $session_id, $user_id )
				);
			}
				
			// Obtém um array com as permissões de usuário
			$_SESSION['userdata']['user_permissions'] = unserialize( $fetch['user_permissions'] );

			// Configura a propriedade dizendo que o usuário está logado
			$this->logged_in = true;
			
			// Configura os dados do usuário para $this->userdata
			$this->userdata = $_SESSION['userdata'];
			
			// Verifica se existe uma URL para redirecionar o usuário
			if ( isset( $_SESSION['goto_url'] ) ) {
				// Passa a URL para uma variável
				$goto_url = urldecode( $_SESSION['goto_url'] );
				
				// Remove a sessão com a URL
				unset( $_SESSION['goto_url'] );
				
				// Redireciona para a página
				echo '<meta http-equiv="Refresh" content="0; url=' . $goto_url . '">';
				echo '<script type="text/javascript">window.location.href = "' . $goto_url . '";</script>';
				//header( 'location: ' . $goto_url );
			}
			
			return;
		} else {
			// O usuário não está logado
			$this->logged_in = false;
			
			// A senha não bateu
			$this->login_error = 'Password does not match.';
		
			// Remove tudo
			$this->logout();
		
			return;
		}
	}
	
	/**
	 * Logout
	 *
	 * Remove tudo do usuário.
	 *
	 * @param bool $redirect Se verdadeiro, redireciona para a página de login
	 * @final
	 */
	protected function logout( $redirect = false ) {
		// Remove all data from $_SESSION['userdata']
		$_SESSION['userdata'] = array();
		
		// Only to make sure (it isn't really needed)
		unset( $_SESSION['userdata'] );
		
		// Regenerates the session ID
		session_regenerate_id();
		
		if ( $redirect === true ) {
			// Send the user to the login page
			$this->goto_login();
		}
	}
	
	/**
	 * Vai para a página de login
	 */
	protected function goto_login() {
		// Verifica se a URL da HOME está configurada
		if ( defined( 'HOME_URI' ) ) {
			// Configura a URL de login
			$login_uri  = HOME_URI . '/login/';
			
			// A página em que o usuário estava
			$_SESSION['goto_url'] = urlencode( $_SERVER['REQUEST_URI'] );
			
			// Redireciona
			echo '<meta http-equiv="Refresh" content="0; url=' . $login_uri . '">';
			echo '<script type="text/javascript">window.location.href = "' . $login_uri . '";</script>';
			// header('location: ' . $login_uri);
		}
		
		return;
	}
	
	/**
	 * Envia para uma página qualquer
	 *
	 * @final
	 */
	final protected function goto_page( $page_uri = null ) {
		if ( isset( $_GET['url'] ) && ! empty( $_GET['url'] ) && ! $page_uri ) {
			// Configura a URL
			$page_uri  = urldecode( $_GET['url'] );
		}
		
		if ( $page_uri ) { 
			// Redireciona
			echo '<meta http-equiv="Refresh" content="0; url=' . $page_uri . '">';
			echo '<script type="text/javascript">window.location.href = "' . $page_uri . '";</script>';
			//header('location: ' . $page_uri);
			return;
		}
	}
	
	/**
	 * Verifica permissões
	 *
	 * @param string $required A permissão requerida
	 * @param array $user_permissions As permissões do usuário
	 * @final
	 */
	final protected function check_permissions( 
		$required = 'any', 
		$user_permissions = array('any')
	) {
		if ( ! is_array( $user_permissions ) ) {
			return;
		}

		// Se o usuário não tiver permissão
		if ( ! in_array( $required, $user_permissions ) ) {
			// Retorna falso
			return false;
		} else {
			return true;
		}
	}
}

O arquivo global-functions.php que está dentro da pasta functions tem a função de __autoload, que carregará todas as nossas classes automaticamente.

Para isso, a classe deverá estar dentro da pasta classes ter o nome class-NomeDaClasse.php (Com letras maiúsculas e minúsculas).

Download

Se você quiser baixar tudo o que já foi feito até agora, segue o link:

Caso queira contribuir com o projeto, acesso no Github:

Perceba que o arquivo que você baixou acima está muito mais adiantado do que este artigo, porém, ainda vamos chegar lá, basta você acompanhar a série MVC em PHP.

Outras partes do artigo

Este artigo está dividido em várias partes, pois seu conteúdo é muito extenso. Também existe uma categoria exclusiva para todo seu conteúdo, chamada de MVC em PHP.

Veja todas as suas partes já publicas nos links abaixo:

Em caso de dúvidas, comente-a!