Aula 02 - Mysqli versus mysql
Apresentação das principais vantagens da extensão mysqli em
relação a mysql (deprecada a partir do PHP 7).
Documentação da extensão em PHP Documentation
Aula 03 - Instalação do MySQL
Fontes e opções para instalação do MySQL para diversos SOs.
Quando tivermos duas instalações do MySQL na mesma máquina (executando em portas diferentes) podemos utilizar na conexão com o banco de dados a opção -P para selecionar a porta desejada.
Aula 04 - Ativando a extensão mysqli
Para verificar se a extensão do mysqli está habilitada em
nossa configuração devemos editar o arquivo php.ini.
Podemos fazer isso de diversas formas, de acordo com o nosso método de execução do servidor. Na linha de comando podemos executar o comando:
Outra forma é acessando o método phpinfo(). Podemos fazer isso através da função em um arquivo PHP.
Podemos também acessar o arquivo diretamente nas configurações do XAMPP.
Devemos procurar por extension=mysqli e habilitá-la. Também devemos habilitar a extensão pdo-mysqli.
Em cada sistema e situação teremos uma configuração específica e devemos verificar cada caso em particular (com o XAMPP essa extensão já vem habilitada).
Aula 05 a 06 - Conectando no banco de dados / Introdução a conexões
persistentes
Para iniciar uma conexão com o banco de dados devemos instanciar o
mysqli() passando como parametro os dados do servidor de
banco de dados.
Aula 07 - Executando comandos no banco de dados
Nessa aula faremos as primeiras interações com o banco de dados.
Diferente do que já vi anteriormente aqui utilizou-se uma sintaxe
diferente para executar as querrys:
Aula 08 - Listando dados do banco
Para recuperar os dados de uma tabela fazemos a query com o
SELECT e em seguida utilizamos a função
mysqli_fetch_assoc() para recuperar os dados.
Podemos percorrer os dados utilizando o loop while():
O método mysqli_fetch_all() tem como parametro padrão o valor MYSQLI_NUM. Isso faz com que todos os valores sejam incluidos em indices numéricos. Para utilizar os nomes dos campos nas chaves mudamos esse parametro para MYSQLI_ASSOC.
Aula 09 - SQL injection
O SQL injection aproveita campos que fazem querys SQL para
injetar códigos capazes de modificar as tabelas do DB. Um exemplo é
injetar em uma variável que irá passar uma string para ser inserida
códigos SQL que irão adicionar ações a query:
Outro exemplo de injection:
Aula 10 - Prepared statement
Para prevenir o SQL injection podemos utilizar o
prepared statement que consiste em não enviar a query
diretamente mas sim tratar o dado que recebemos antes de inseri-lo
na requisição:
Esse parametro filtra os dados recebidos para os dados permitidos para aquela consulta, evitando que se injete dados inválidos.
Note que precisamos alterar o valor a ser inserido na query (devemos retirar a variável e inserir o '?').
Podemos colocar mais que 1 parametro no bind_param. Nesse caso devemos indicar a letra do tipo de cada variável e as demais variáveis.
$stmt->bind_param('ii', $id1, $id2);
Aula 11 a 15 - CRUD listando dados / CRUD visualizando um único
usuário / CRUD removendo registros / CRUD inserindo dados / CRUD
edição de registros
Iniciamos um documento com html padrão e uma tabela.
Criamos o arquivo de conexão com o DB e, uma dica. No arquivo de conexão foi utilizado um return com o nome da variável de conexão. Dessa forma nada abaixo do retrun é executado.
Em seguida recuperamos os dados do DB com o query e fetch_all e transferimos os dados para a tabela.
Criamos uma página para exibir cada dado da lista individualmente. Nessa página criamos uma query utilizando o prepared statement para proteger as requisições GET. Recuperamos os dados do registro com o fetch_assoc.
Para a página de remoção utilizamos a mesma estrutura de requisição com prepared statement da página de seleção porém substituimos o SELECT por DELETE.
Para adicionar registros mantivemos a mesma estrutura dos demais arquivos. As diferenças são que utilizamos o método POST para envio dos dados e alteramos o parametro de statement e 'i'(inteiro) para 's'(string).
Ajustamos a query SQL para INSERT INTO e a condicional para monitorar o envio das informações verifica a variável gloabal $_SERVER['REQUEST_METHOD'] == POST. Normalmente eu faço a verificação de alguma variável enviada (isset($_POST['valor'])).
Para o arquvo de edição temos uma mistura dos arquivos de listagem e inserção. Recuperamos os dados da item a ser alterado com o SELECT executado com prepared statement. Para a alteração dos dados enviamos os dados via POST para uma query do tipo UPDATE...SET para alterar o conteudo do campo. Nesse caso como precisamos passar o novo valor do campo e o id de identificação do registro utilizamos o statement com o bind_param('si') passando as duas variáveis (string e numérica).
Aula 05 - Conectando no banco de dados
Aula 05 - Conectando no banco de dados

Documentação da extensão em PHP Documentation

Quando tivermos duas instalações do MySQL na mesma máquina (executando em portas diferentes) podemos utilizar na conexão com o banco de dados a opção -P para selecionar a porta desejada.

Podemos fazer isso de diversas formas, de acordo com o nosso método de execução do servidor. Na linha de comando podemos executar o comando:
# php -i
Com esse comando temos diversas informações sobre o PHP entre elas o
path para o arquivo. Outra forma é acessando o método phpinfo(). Podemos fazer isso através da função em um arquivo PHP.
Podemos também acessar o arquivo diretamente nas configurações do XAMPP.
Devemos procurar por extension=mysqli e habilitá-la. Também devemos habilitar a extensão pdo-mysqli.
Em cada sistema e situação teremos uma configuração específica e devemos verificar cada caso em particular (com o XAMPP essa extensão já vem habilitada).

$conn = new mysqli('servidor', 'usuário',
'senha', 'nome_do_banco', porta);
Feita a conexão podemos fazer um teste para validá-la ou retornar
erros caso existam. Para isso basta verificarmos alguns parametros
do objeto mysqli instanciado:
if ($conn->connect_errno) {
die('Falhou em conectar:(' . $mysql->connect_errno . ') ' . $mysql->connect_error);
} else {
echo 'Connected';
echo $conn->host_info;
print_r($conn);
}
Pode ser necessário utilizar conexões persistentes entre a aplicação PHP e o banco MySQL. Para fazer isso é necessário ajustar algumas configurações no arquivo php.ini ou incluir essas propriedades diretamente no arquivo através do método ini_set().
As propriedades a serem alteradas para que a conexão seja persistente são:
die('Falhou em conectar:(' . $mysql->connect_errno . ') ' . $mysql->connect_error);
} else {
echo 'Connected';
echo $conn->host_info;
print_r($conn);
}
Pode ser necessário utilizar conexões persistentes entre a aplicação PHP e o banco MySQL. Para fazer isso é necessário ajustar algumas configurações no arquivo php.ini ou incluir essas propriedades diretamente no arquivo através do método ini_set().
As propriedades a serem alteradas para que a conexão seja persistente são:
ini_set('mysqli.allow_persistent', 'On');
ini_set('mysqli.max_persistent', -1);
ini_set('mysqli.max_links', -1);
ini_set('mysqli.max_persistent', -1);
ini_set('mysqli.max_links', -1);

$sql = 'show tables';
$result = $conn->query($sql);
Ao invés do comando:
$result = mysqli_query($conn, $sql);
Em seguida foi incluido um teste lógico para receber o resultado da
inclusão da tabela e verificar se ela já existe. Esse modo de
verificação não funcionou na minha versão pois o próprio
mysqli já envia uma mensagem de erro. $result = $conn->query($sql);
Ao invés do comando:
$result = mysqli_query($conn, $sql);
Método proposto (como a query retorna um booleano caso false não
cria a tabela):
if (!$result = $conn->query($create_table)) { echo 'Tabela users já existe'; };
Minha solução para o problema (verificar se existe a tabela e caso positivo retornar um erro):
$show_tables = 'show tables';
$result = $conn->query($show_tables);
$temp = array();
while ($linha = mysqli_fetch_assoc($result)) {
foreach ($linha as $key => $value) {
$temp[] = ($value);
};
}
if (!array_search('users', $temp)) {
$conn->query($create_table);
} else {
echo 'Tabela já existe
';
}
if (!$result = $conn->query($create_table)) { echo 'Tabela users já existe'; };
Minha solução para o problema (verificar se existe a tabela e caso positivo retornar um erro):
$show_tables = 'show tables';
$result = $conn->query($show_tables);
$temp = array();
while ($linha = mysqli_fetch_assoc($result)) {
foreach ($linha as $key => $value) {
$temp[] = ($value);
};
}
if (!array_search('users', $temp)) {
$conn->query($create_table);
} else {
echo 'Tabela já existe
';
}

Podemos percorrer os dados utilizando o loop while():
$result = $conn->query('SELECT * FROM users');
while ($user = $result->fetch_assoc()) {
echo $user['email'];
}
Podemos também utilizar o foreach() porém nesse caso
precisamos utilizar o mysqli_fetch_all(): while ($user = $result->fetch_assoc()) {
echo $user['email'];
}
foreach ($result->fetch_all() as $user) {
echo $user[0] . ' - ' . $user[1];
}
OS métodos fetch limpam a consulta, portanto uma vez que
todos os dados estiverem processados a query fica limpa. echo $user[0] . ' - ' . $user[1];
}
O método mysqli_fetch_all() tem como parametro padrão o valor MYSQLI_NUM. Isso faz com que todos os valores sejam incluidos em indices numéricos. Para utilizar os nomes dos campos nas chaves mudamos esse parametro para MYSQLI_ASSOC.

Query original:
$result = $conn->multi_query('INSERT INTO users (email) VALUES ("' . $email . '")');
Código inserido na variável $email:
[email protected]");TRUNCATE users; INSERT INTO users(email) VALUE ("[email protected]
Passando essa linha para o campo (no exemplo diretamente para o GET na url) teremos a seguinte query enviada para o DB:
INSERT INTO users(email) VALUE ("[email protected]");TRUNCATE users; INSERT INTO users(email) VALUE ("[email protected]");
O comando SQL TRUNCATE é como a instrução DELETE, porém
sem usar a cláusula WHERE. Portanto, é usada para apagar
completamente o conteúdo de uma tabela e 'zera' os valores de
auto-incremento, coisa que o comando DELETE não faz.
$result = $conn->multi_query('INSERT INTO users (email) VALUES ("' . $email . '")');
Código inserido na variável $email:
[email protected]");TRUNCATE users; INSERT INTO users(email) VALUE ("[email protected]
Passando essa linha para o campo (no exemplo diretamente para o GET na url) teremos a seguinte query enviada para o DB:
INSERT INTO users(email) VALUE ("[email protected]");TRUNCATE users; INSERT INTO users(email) VALUE ("[email protected]");
Outro exemplo de injection:
$result = $conn->query('SELECT * FROM users WHERE id > ' .
$id);
Código injetado:
4 OR 1=1% UNION SELECT * FROM products WHERE 1=1
Código enviado ao DB:
SELECT * FROM users WHERE id > 4 OR 1=1% UNION SELECT * FROM products WHERE 1=1;
Código injetado:
4 OR 1=1% UNION SELECT * FROM products WHERE 1=1
Código enviado ao DB:
SELECT * FROM users WHERE id > 4 OR 1=1% UNION SELECT * FROM products WHERE 1=1;

Linha original:
$result = $conn->query('SELECT * FROM users WHERE id > ' . $id);
Alteração para o statement.
$stmt = $conn->prepare('SELECT * FROM users WHERE id > ?');
$stmt->bind_param('i', $id);
$stmt->execute();
$result = $stmt->get_result();
O bind_param pode ser 'i': inteiro, 's': string, 'b': blob e
'd': double. $result = $conn->query('SELECT * FROM users WHERE id > ' . $id);
Alteração para o statement.
$stmt = $conn->prepare('SELECT * FROM users WHERE id > ?');
$stmt->bind_param('i', $id);
$stmt->execute();
$result = $stmt->get_result();
Esse parametro filtra os dados recebidos para os dados permitidos para aquela consulta, evitando que se injete dados inválidos.
Note que precisamos alterar o valor a ser inserido na query (devemos retirar a variável e inserir o '?').
Podemos colocar mais que 1 parametro no bind_param. Nesse caso devemos indicar a letra do tipo de cada variável e as demais variáveis.
$stmt->bind_param('ii', $id1, $id2);

Criamos o arquivo de conexão com o DB e, uma dica. No arquivo de conexão foi utilizado um return com o nome da variável de conexão. Dessa forma nada abaixo do retrun é executado.
Em seguida recuperamos os dados do DB com o query e fetch_all e transferimos os dados para a tabela.
Criamos uma página para exibir cada dado da lista individualmente. Nessa página criamos uma query utilizando o prepared statement para proteger as requisições GET. Recuperamos os dados do registro com o fetch_assoc.
Para a página de remoção utilizamos a mesma estrutura de requisição com prepared statement da página de seleção porém substituimos o SELECT por DELETE.
Para adicionar registros mantivemos a mesma estrutura dos demais arquivos. As diferenças são que utilizamos o método POST para envio dos dados e alteramos o parametro de statement e 'i'(inteiro) para 's'(string).
Ajustamos a query SQL para INSERT INTO e a condicional para monitorar o envio das informações verifica a variável gloabal $_SERVER['REQUEST_METHOD'] == POST. Normalmente eu faço a verificação de alguma variável enviada (isset($_POST['valor'])).
Para o arquvo de edição temos uma mistura dos arquivos de listagem e inserção. Recuperamos os dados da item a ser alterado com o SELECT executado com prepared statement. Para a alteração dos dados enviamos os dados via POST para uma query do tipo UPDATE...SET para alterar o conteudo do campo. Nesse caso como precisamos passar o novo valor do campo e o id de identificação do registro utilizamos o statement com o bind_param('si') passando as duas variáveis (string e numérica).

