CRUD em PHP com PDO: tudo que você precisa saber

Se você está começando no mundo da programação ou deseja aprimorar suas habilidades em PHP, criar um CRUD em PHP com PDO é um passo essencial. Neste artigo, irei guiá-lo por todo o processo, demonstrando como o PDO pode ser utilizado para desenvolver uma interface robusta e segura com bancos de dados, especificamente utilizando o MySQL. Exploraremos desde a conexão inicial até a manipulação avançada de dados, abordando também consultas parametrizadas que ajudam a evitar vulnerabilidades comuns, como injeções de SQL.

Ao longo deste artigo, você descobrirá como o PDO facilita o desenvolvimento de sistemas web dinâmicos e eficientes, com exemplos práticos que podem ser aplicados diretamente em seus projetos. Se você deseja ir além do básico e construir sistemas PHP profissionais, continue lendo e veja como criar um CRUD completo com PDO!

Pré-requisitos

Para acompanhar este conteúdo, você precisa ter noções básicas de PHP e SQL. É muito provável que você esteja aqui porque já possui uma compreensão básica da linguagem PHP. No entanto, se você ainda não tem conhecimento prévio em SQL, não se preocupe; eu acredito que você conseguirá entender todos os pontos abordados.

Contudo, se você não tem familiaridade com SQL, recomendo que estude as declarações SQL mencionadas neste artigo. Compreender o significado delas facilitará a assimilação das informações discutidas, além de permitir que você as aplique no seu desenvolvimento, ampliando sua experiência como programador.

Vale destacar que este artigo não se aprofunda nas declarações SQL ou nos aplicativos utilizados para gerenciar um banco de dados em MySQL. Além disso, em relação ao seu conhecimento sobre PHP, é compreensível se você ainda não dominar os conceitos de programação orientada a objetos, como “O que é uma classe?” ou “O que é uma instância?”. O PDO é construído com base na Orientação a Objetos, e você encontrará termos como método, atributo, classe e instância ao longo do texto.

Portanto, prepare-se para explorar um artigo que aborda conceitos de Orientação a Objetos. Mesmo que você ainda não esteja completamente confortável em programar dentro desse paradigma, tenho certeza de que, ao seguir as orientações cuidadosamente, você aproveitará bastante o conteúdo.

Criando a Conexão

Para criar um CRUD em PHP com PDO, o primeiro passo é estabelecer a conexão com o banco de dados utilizando a classe PDO. Fazemos isso da seguinte maneira:

Por exemplo, no caso de usar MySQL:

$pdo = new PDO("mysql:host=meu_servidor;dbname=meubanco", "meu_usuario", "minha_senha");

O que aparece entre as primeiras apas é conhecido muitas vezes como DSN (Data Source Name), mas o correto é entender como uma string de conexão que especifica informações sobre uma fonte de dados. Veja o que a Wikipedia diz:

É passado o código para um driver ou provedor subjacente com o objetivo de iniciar a conexão. Embora seja geralmente usado para conexão com bancos de dados, a fonte de dados também pode ser uma planilha eletrônica ou um arquivo de texto.

A string de conexão pode incluir atributos como o nome do driver, servidor e banco de dados, além de informações de segurança como nome de usuário e senha. (Fonte: Jota Naici, acessado em 21/06/2019).

Por exemplo, para conectar a um servidor MySQL com o IP 192.168.0.10, banco de dados erp_database, usuário db_admin e senha Abcd1234, você pode usar a seguinte conexão:

$pdo = new PDO("mysql:host=192.168.0.10;dbname=erp_database", "db_admin", "Abcd1234");

É importante lembrar que, se por acaso esta configuração for semelhante a algum banco de dados real, será pura coincidência.

Em um ambiente de desenvolvimento, os programadores costumam usar o usuário root, mas em um ambiente de produção, eles devem usar um usuário com permissões limitadas para garantir mais segurança.

Conectar ao banco de dados requer apenas essa linha no PHP, mas frequentemente adicionamos algumas definições como o comportamento da classe em caso de erro e o charset, por exemplo.

Você pode fazer essas definições da seguinte maneira:

$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

Você define o atributo diretamente na instância do objeto PDO. Além disso, pode executar comandos assim que estabelecer a conexão.

Por exemplo:

$pdo->exec("SET NAMES utf8");

No entanto, você também pode definir isso no momento em que instancia o PDO:

$pdo->exec("SET NAMES utf8");

Faça da maneira que preferir!

Recomendo que coloque essa declaração dentro de um bloco try e catch para tratar possíveis exceções, como no exemplo abaixo:

<?php
try {
    $pdo = new PDO(
        "mysql:host=192.168.0.10;dbname=erp_database", 
        "db_admin", 
        "Abcd1234", 
        array(
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, 
            PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"
        )
    );
} catch (PDOException $e) {
    echo 'Erro: ' . $e->getMessage();
}

Criando uma estutura de banco de dados

Antes de listarmos ou manipulamos dados, precisamos garantir que temos uma tabela criada. Aqui está um exemplo de uma tabela chamada tb_clientes para nossos exemplos:

CREATE TABLE tb_clientes (
    id INT AUTO_INCREMENT PRIMARY KEY,
    primeiro_nome VARCHAR(50) NOT NULL,
    sobre_nome VARCHAR(50) NOT NULL,
    email VARCHAR(100),
    celular VARCHAR(20)
);

Essa tabela contém campos essenciais para armazenar informações de clientes, como nome, sobrenome, email e celular.

Agora que a tabela foi criada, embora abordaremos a inserção de dados mais adiante, já podemos inserir alguns exemplos para facilitar as consultas nos próximos passos:

INSERT INTO tb_clientes (primeiro_nome, sobre_nome, email, celular)
VALUES 
('João', 'Silva', 'joao.silva@email.com', '9999-1234'),
('Maria', 'Oliveira', 'maria.oliveira@email.com', '9888-5678'),
('Pedro', 'Santos', 'pedro.santos@email.com', '9777-9101');

Com esses dados inseridos, já temos uma base para os próximos exemplos de manipulação e listagem de informações.

Listando dados

Agora que você já configurou a conexão e inseriu dados no banco, é hora de criar um CRUD em PHP com PDO para listar esses registros. Então, para avançar nessa primeira etapa, vamos usar o método prepare para criar uma consulta SQL segura e o método fetch para retornar os dados:

try {
    $stmt = $pdo->prepare("SELECT * FROM tb_clientes");
    $stmt->execute();

    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
        echo "Nome: " . $row['primeiro_nome'] . " " . $row['sobre_nome'] . "<br>";
    }
} catch (PDOException $e) {
    echo "Erro ao buscar dados: " . $e->getMessage();
}

Consultas Parametrizadas para Segurança

Usar consultas parametrizadas é essencial para evitar ataques de injeção de SQL. Saiba mais sobre injeção de SQL nesse artigo. Vamos buscar um cliente pelo seu id, utilizando parâmetros:

try {
    $stmt = $pdo->prepare("SELECT * FROM tb_clientes WHERE id = :id");
    $stmt->bindValue(':id', $id, PDO::PARAM_INT);

    if ($stmt->execute()) {
        while ($rs = $stmt->fetch(PDO::FETCH_OBJ)) {
            var_dump($rs); // O resultado neste caso gera um objeto por linha
        }
    } else {
        echo "Erro: Não foi possível recuperar os dados do banco de dados";
    }
} catch (PDOException $erro) {
    echo "Erro: " . $erro->getMessage();
}

O método bindValue vincula o valor da variável $id ao parâmetro nomeado. Então, aqui, o método bindValue garante que o valor passado seja tratado de forma segura, prevenindo injeção de SQL.

Se o que você quer passar for uma string, veja o exemplo abaixo:

try {
    $stmt = $pdo->prepare("SELECT * FROM tb_clientes WHERE primeiro_nome LIKE :p_nome OR sobre_nome LIKE :s_nome");
    $stmt->bindValue(':p_nome', '%' . $p_nome . '%', PDO::PARAM_STR);
    $stmt->bindValue(':s_nome', '%' . $s_nome . '%', PDO::PARAM_STR);

    if ($stmt->execute()) {
        while ($rs = $stmt->fetch(PDO::FETCH_OBJ)) {
            var_dump($rs); // O resultado neste caso gera um objeto por linha
        }
    } else {
        echo "Erro: Não foi possível recuperar os dados do banco de dados";
    }
} catch (PDOException $erro) {
    echo "Erro: " . $erro->getMessage();
}

Usamos dois parâmetros: um para o primeiro nome e outro para o sobrenome, e tratamos ambos como strings.

Para verificar se bindValue foi bem-sucedido, você pode usar var_dump para retornar um valor booleano.

var_dump($stmt->bindValue(':p_nome', '%' . $p_nome . '%', PDO::PARAM_STR)); // Retornará true ou false

Depois de vincular os valores, o método execute executa a consulta, retornando um valor booleano. Se o retorno for positivo, você pode buscar os resultados com fetch:

if ($stmt->execute()) {
    while ($rs = $stmt->fetch(PDO::FETCH_OBJ)) {
        var_dump($rs); // O resultado neste caso gera um objeto por linha
    }
} else {
    echo "Erro: Não foi possível recuperar os dados do banco de dados";
}

Perceba que, no if, se o teste retornar false, o else executa e apresenta a mensagem de erro.

Uma vez tendo resultado positivo em execute(), pode-se buscar os resultados utilizando um método apropriado. Neste caso como espera-se iterar linha a linha, utiliza-se o fetch(). O fetch retorna uma linha a cada iteração e é possivel determinar como se deseja este retorno. No exemplo esperamos que cada row, seja um objeto, tendo cada coluna como um atributo:

while ($rs = $stmt->fetch(PDO::FETCH_OBJ)) {
    var_dump($rs); // O resultado neste caso gera um objeto por linha
}

Você pode também buscar os dados como arrays associativos:

while ($rs = $stmt->fetch(PDO::FETCH_ASSOC)) {
    var_dump($rs); // O resultado neste caso gera um array associativo por linha
}

Se você quiser recuperar todos os dados de uma só vez, use fetchAll:

if ($stmt->execute()) {
    var_dump($stmt->fetchAll()); // Retorna um array multidimensional com arrays representando rows
} else {
    echo "Erro: Não foi possível recuperar os dados do banco de dados";
}

Se quiser mais detalhes sobre o uso de fetch, recomendo que consulte a documentação oficial: https://www.php.net/manual/pt_BR/pdostatement.fetch.php

Caso deseje retornar o resultado como uma classe, você pode fazer o seguinte:

if ($stmt->execute()) {
    var_dump($stmt->fetchAll(PDO::FETCH_CLASS)); // Retorna um array de objetos com resultados vinculados a suas propriedades
} else {
    echo "Erro: Não foi possível recuperar os dados do banco de dados";
}

Ou especificar uma classe para os objetos:

if ($stmt->execute()) {
    var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'Cliente')); // Retorna um array de objetos 'Cliente' com resultados vinculados a suas propriedades
} else {
    echo "Erro: Não foi possível recuperar os dados do banco de dados";
}

Se você estiver buscando apenas uma linha, o método fetch será mais eficiente:

try {
    $stmt = $pdo->prepare("SELECT * FROM tb_clientes WHERE id = :id");
    $stmt->bindValue(':id', $id, PDO::PARAM_INT);

    if ($stmt->execute()) {
        $cliente = $stmt->fetch(PDO::FETCH_OBJ); // O resultado neste caso gera um objeto
        $id = $cliente->id;
        $p_nome = $cliente->primeiro_nome;
        $s_nome = $cliente->sobre_nome;
        $email = $cliente->email;
        $celular = $cliente->celular;
    } else {
        echo "Erro: Não foi possível recuperar os dados do banco de dados";
    }
} catch (PDOException $erro) {
    echo "Erro: " . $erro->getMessage();
}

Manipulando retorno de forma avançada

Embora eu já tenha apresentado o código acima, agora o detalhei para facilitar a compreensão do processo de extração de dados do retorno. É importante destacar que você pode tratar o fetch de diferentes maneiras:

if ($stmt->execute()) {
    $cliente = $stmt->fetch(PDO::FETCH_ASSOC); // O resultado neste caso gera um array associativo
    $id = $cliente['id'];
    $p_nome = $cliente['primeiro_nome'];
    $s_nome = $cliente['sobre_nome'];
    $email = $cliente['email'];
    $celular = $cliente['celular'];
} else {
    echo "Erro: Não foi possível recuperar os dados do banco de dados";
}

No entanto, se você deseja criar um objeto DAO ou Active Record que vincule o resultado diretamente à classe, pode usar fetchObject:

if ($stmt->execute()) {
    $cliente = $stmt->fetchObject(__CLASS__); // O resultado neste caso gera um objeto da classe atual
} else {
    echo "Erro: Não foi possível recuperar os dados do banco de dados";
}

Para isso funcionar corretamente, a classe precisa utilizar os métodos mágicos __set() e __get(). A seguir, você encontra um exemplo de uma classe simplificada para ilustrar essa construção:

<?php
/**
 * Classe Cliente
 *
 */
class Cliente
{
    protected $pdo;
    protected $atributos;

    public function __construct($host, $database, $user, $pass)
    {
        try {
            $this->pdo = new PDO("mysql:host={$host};dbname={$database}", $user, $pass, 
            array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
        } catch (PDOException $e) {
            echo 'Erro: ' . $e->getMessage();
        }
    }

    public function __set($atributo, $valor)
    {
        $this->atributos[$atributo] = $valor;
    }

    public function __get($atributo)
    {
        return $this->atributos[$atributo];
    }

    public function find(int $id)
    {
        try {
            $stmt = $this->pdo->prepare("SELECT * FROM tb_clientes WHERE id = :id");
            $stmt->bindValue(':id', $id, PDO::PARAM_INT);

            if ($stmt->execute()) {
                return $stmt->fetchObject(__CLASS__); // O resultado neste caso gera um objeto da classe Cliente
            } else {
                echo "Erro: Não foi possível recuperar os dados do banco de dados";
            }
        } catch (PDOException $erro) {
            echo "Erro: " . $erro->getMessage();
        }
    }
}

Agora, veja um exemplo de uso:

$clienteDao = new Cliente('192.168.0.10', 'erp_database', 'db_admin', 'Abcd1234');
$cliente = $clienteDao->find(1);

echo $cliente->primeiro_nome . ' ' . $cliente->sobre_nome;

Eu simplifiquei este exemplo para fins de demonstração. Se quiser conferir exemplos completos e funcionais, consulte outros artigos deste blog.

Inserindo, atualizando e excluíndo dados

Agora vamos inserir novos clientes no banco de dados. Para isso, utilizamos parâmetros nomeados para garantir segurança:

<?php
$stmt = $pdo->prepare("INSERT INTO tb_clientes (primeiro_nome, sobre_nome, email, celular) VALUES (:p_nome, :s_nome, :email, :celular)");

$stmt->bindValue('p_nome', $primeiro_nome, PDO::PARAM_STR);
$stmt->bindValue('s_nome', $sobre_nome, PDO::PARAM_STR);
$stmt->bindValue('email', $email, PDO::PARAM_STR);
$stmt->bindValue('celular', $celular, PDO::PARAM_STR);

if ($stmt->execute()) {
    if ($stmt->rowCount() > 0) {
        echo "Cadastro efetuado com sucesso!";
    } else {
        echo "Não foi possível fazer o cadastro.";
    }
} else {
    throw new PDOException("Erro: Não foi possível executar a declaração SQL");
}

Embora os blocos try e catch tenham sido omitidos, é essencial incluí-los para tratar exceções corretamente em caso de falhas.

Além disso, você deve estar ciente de que é necessário passar as variáveis com seus respectivos valores, mas eu omiti esses detalhes para manter o exemplo mais claro.

Você também pode passar todos os dados de uma só vez no momento da execução. Mas, embora isso impeça a definição dos tipos de dados como bindValue ou bindParam permite, é importante saber que é possível. Portanto, primeiro, criamos o array e, em seguida, o passamos como argumento no execute:

<?php
$valores = [
    'primeiro_nome' => 'João',
    'sobre_nome' => 'Silva',
    'email' => 'jsilva@teste.com.br',
    'celular' => '9999-0000'
];

$stmt = $pdo->prepare("INSERT INTO tb_clientes (primeiro_nome, sobre_nome, email, celular) VALUES (:primeiro_nome, :sobre_nome, :email, :celular)");

if ($stmt->execute($valores)) {
    if ($stmt->rowCount() > 0) {
        echo "Cadastro efetuado com sucesso!";
    } else {
        echo "Não foi possível fazer o cadastro.";
    }
} else {
    throw new PDOException("Erro: Não foi possível executar a declaração SQL");
}

Atualizando dados

Assim como inserimos, podemos atualizar os registros de forma semelhante. Vamos atualizar o email de um cliente:

<?php
$stmt = $pdo->prepare("UPDATE tb_clientes SET primeiro_nome=:p_nome, sobre_nome=:s_nome, email=:email, celular=:celular WHERE id = :id");

$stmt->bindValue('p_nome', $primeiro_nome, PDO::PARAM_STR);
$stmt->bindValue('s_nome', $sobre_nome, PDO::PARAM_STR);
$stmt->bindValue('email', $email, PDO::PARAM_STR);
$stmt->bindValue('celular', $celular, PDO::PARAM_STR);
$stmt->bindValue('id', $id, PDO::PARAM_INT);

if ($stmt->execute()) {
    if ($stmt->rowCount() > 0) {
        echo "Atualização efetuada com sucesso!";
    } else {
        throw new PDOException("Erro: Não foi possível executar a declaração SQL");
    }
} else {
    throw new PDOException("Erro: Não foi possível executar a declaração SQL");
}

Excluindo Dados

Finalmente, para excluir um cliente, também usamos consultas parametrizadas para evitar qualquer vulnerabilidade, apenas mudando a declaração SQL para o comando DELETE:

<?php
$stmt = $conexao->prepare("DELETE FROM tb_clientes WHERE id = :id");

$stmt->bindValue(':id', $id, PDO::PARAM_INT);

if ($stmt->execute()) {
    echo "Registro foi excluído com êxito";
} else {
    throw new PDOException("Erro: Não foi possível executar a declaração SQL");
}

Você também pode vincular as variáveis à declaração por referência, utilizando o bindParam:

<?php
$stmt = $pdo->prepare("INSERT INTO tb_clientes (primeiro_nome, sobre_nome, email, celular) VALUES (:p_nome, :s_nome, :email, :celular)");

$stmt->bindParam('p_nome', $primeiro_nome, PDO::PARAM_STR);
$stmt->bindParam('s_nome', $sobre_nome, PDO::PARAM_STR);
$stmt->bindParam('email', $email, PDO::PARAM_STR);
$stmt->bindParam('celular', $celular, PDO::PARAM_STR);

if ($stmt->execute()) {
    if ($stmt->rowCount() > 0) {
        echo "Cadastro efetuado com sucesso!";
    } else {
        echo "Não foi possível fazer o cadastro.";
    }
} else {
    throw new PDOException("Erro: Não foi possível executar a declaração SQL");
}
Diferença entre bindParam e bindValue

À primeira vista, pode parecer que não há diferença entre bindParam e bindValue. No entanto, em alguns casos, você pode querer fazer algo como:

<?php
$stmt->bindParam('p_nome', $this->getNome(), PDO::PARAM_STR);

// Ou para fazer um teste:
$stmt->bindParam('id', 25, PDO::PARAM_INT);

Esses casos gerariam erros, porque bindParam faz a atribuição para a variável, e não para o valor diretamente, como bindValue faz. O código a seguir funcionaria corretamente:

<?php
$stmt->bindValue('p_nome', $this->getNome(), PDO::PARAM_STR);

// Ou para fazer um teste:
$stmt->bindValue('id', 25, PDO::PARAM_INT);

Embora bindParam funcione bem na maioria dos casos, imagine um padrão de Gateway de conexão, onde você passa um objeto container com os dados a serem armazenados. Veja o exemplo:

<?php
class Produto
{
    protected $descricao;
    protected $valor;

    public function __construct(string $descricao)
    {
        $this->descricao = $descricao;
        $this->valor = 0.0;
    }

    public function getDescricao()
    {
        return $this->descricao;
    }

    public function getValor(): float
    {
        return $this->valor;
    }

    public function getValorAsString(): string
    {
        return (string) $this->getValor();
    }

    public function setValor(float $valor)
    {
        if($valor > 0.0) {
            $this->valor = $valor;
        } else {
            throw new Exception("Valor inválido");
        }
    }
}

class DaoProduto
{
    protected $pdo;

    public function __construct($host, $database, $user, $pass)
    {
        $this->pdo = new PDO("mysql:host={$host};dbname={$database}", $user, $pass,
        array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
    }

    public function store(Produto $produto)
    {
        $stmt = $this->pdo->prepare("INSERT INTO tb_produtos (descricao, valor) VALUES (:descricao, :valor)");

        $stmt->bindParam(':descricao', $produto->getDescricao(), PDO::PARAM_STR); // Corrigido para usar bindParam corretamente
        $stmt->bindParam(':valor', $produto->getValorAsString(), PDO::PARAM_STR); // Corrigido para remover erro de variável extra

        if ($stmt->execute()) {
            if ($stmt->rowCount() > 0) {
                echo "Cadastro efetuado com sucesso!";
            } else {
                echo "Não foi possível fazer o cadastro.";
            }
        } else {
            throw new PDOException("Erro: Não foi possível executar a declaração SQL");
        }
    }
}

Então, ao testar essa classe:

try {
    $daoProduto = new DaoProduto('192.168.0.10', 'erp_database', 'db_admin', 'Abcd1234');

    $produto = new Produto("Mouse Pad");
    $produto->setValor(25.45);

    $daoProduto->store($produto); // Agora deve funcionar corretamente

} catch(Exception $e) {
    var_dump($e->getTrace());
}

Eu simplifiquei este exemplo para manter o foco no objetivo principal. Entretanto, em um ambiente real, você geralmente não criaria uma nova instância PDO para cada conexão. Contudo, para saber mais, consulte o artigo completo neste blog sobre a criação de um CRUD completo.

Em conclusão, o bindParam faz uma referência à variável no momento em que o método execute() é chamado, enquanto isso, o bindValue atribui o valor diretamente ao objeto PDOStatement.

Dicas de Segurança

Adicionalmente, além de usar consultas parametrizadas, aqui estão mais algumas dicas de segurança:

  1. Sanitização de Dados: sempre filtre os dados recebidos de usuários com funções como filter_var() para evitar entradas maliciosas.
  2. Conexões Seguras: Utilize SSL para garantir que a comunicação com o banco de dados seja segura, especialmente em ambientes de produção.
  3. Usuários com Permissões Limitadas: Nunca use o usuário root em um ambiente de produção. Crie um usuário com permissões específicas para o sistema.

Conclusão

Seguindo este tutorial, você poderá criar um CRUD em PHP com PDO de maneira eficiente, aplicando boas práticas de segurança e otimização.. Primeiramente, destacamos a importância da conexão com o banco de dados e, em seguida, explicamos o uso de consultas parametrizadas para aumentar a segurança do sistema. Além disso, detalhamos o uso de diferentes métodos, como fetch() e fetchAll(), para tratar os dados retornados das consultas. Por fim, exemplificamos os métodos de inserção, atualização e exclusão de dados. Portanto, ao aplicar o que discutimos, você conseguirá construir sistemas mais robustos e seguros.

[]’s

4 comentários em “CRUD em PHP com PDO: tudo que você precisa saber”

  1. Cara, acho louvável sua atitude de compartilhar seus conhecimentos da forma que faz. Procura simplificar conceitos que nem são tão simples e me parece que você gosta disso. Sinceramente louvo sua atitude.

    Gostaria de levantar uma questão meio delicada e espero que não entenda que estou te criticando. Estou querendo sinceramente ajudar. Imagino ainda facilitaria a vida de quem visita seu site: você já pensou em utilizar o Joomla em seu site? Sabe porque pergunto, por que com Joomla realmente podemos trabalhar com categorias reais com facilidade (com wp dá mas não é nativo) e assim o usuário encontra tudo que existe no site com grande facilidade. Veja o meu site, onde todo o conteúdo encontra-se disponível no menu superior:
    https://ribafs.org

    Eu tento encontrar o que existe em sites com o wordpress mas não é simples.

    Atualmente estou estudando uma forma de criar um site parecido e com as mesmas facilidades de um CMS mas usando uma conta gratuita no GitHib. Como você é um cara que tem um grande conhecimento da área e gosta disso, se interessar podemos trocar ideias sobre o assunto. Pode até não publicar este comentário ou despublicar, mas gostaria de trocar ideias. Imagina poder criar um site bonito, de forma confortável tipo num CMS e ainda gratuito?

    1. Ótimo Ribamar! Tenho estudado a migração para uma hospedagem legal e uma grande mudança. Certamente considerarei a sua sugestão! Muito obrigado! A respeito do ensinar você tem razão, eu gosto muito mesmo. Sempre lembro de quando jovem e na minha época o quão difícil era encontrar informações. Além disso, muitos ao invés de ensinar, utilizavam conhecimento para se vã gloriar, atitude que nunca apreciei. Mas para mim é um presente muito grande e significativo quando consigo de fato ajudar outros. Ministrei treinamentos e atuei como professor em algumas franquias em épocas louváveis, quando o professor tinha um livro, lousa e tempo para explicar. Hoje, me esforço para conseguir investir em algo no blog. É muito trabalhoso e envolve muitas pesquisas para não expor ideias erradas e nem pretensiosas. Fico feliz que tenha apreciado. Novamente, obrigado e abraço!

  2. Antonio Almeida

    Excelentes comentários de dois grandes mestres no assunto. Nada a declarar, nesse momento, só tenho que aprender. Muito obrigado por preciosas informações…

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Rolar para cima