PHP Ler e Escrever Arquivos
Tudo o que um programa guarda em variáveis some quando ele termina. Para lembrar de alguma coisa até a próxima vez (a lista de compras, os recados dos clientes, o registro das vendas do dia), o programa precisa gravar num arquivo. Nesta aula você vai ler e escrever arquivos de texto, criar pastas, listar e apagar arquivos, e entender as mensagens que o PHP mostra quando algo dá errado.
- O jeito curto:
file_put_contents(gravar) efile_get_contents(ler), e como acrescentar comFILE_APPEND. - Ler um arquivo como uma lista de linhas com
file(). - O jeito "passo a passo":
fopen,fgets,fwriteefclose, e quando ele vale a pena. - Perguntar se algo existe:
file_exists,is_file,is_dir. - Pastas:
mkdir,scandir,rmdir; apagar comunlink. - Os erros reais: arquivo inexistente,
Permission denied,File exists.
Os exemplos rodam na pasta /home/ana/arq da máquina da Ana. No editor do guia, os arquivos são criados num disco de mentira, na memória do navegador: pode gravar à vontade.
A ideia: um caderno na gaveta
Um arquivo é como um caderno guardado numa gaveta. Para usar, você precisa saber o nome do caderno e em que gaveta (pasta) ele está. Aí pode ler o que está escrito, escrever por cima (apagando o que havia) ou continuar escrevendo na próxima linha em branco. O PHP tem uma função para cada uma dessas ações.
Gravar e ler de uma vez
As duas funções mais usadas fazem tudo numa linha só:
file_put_contents("pôr o conteúdo no arquivo"): grava um texto num arquivo. Se o arquivo não existe, ele é criado.file_get_contents("pegar o conteúdo do arquivo"): devolve todo o texto do arquivo, como uma string.
<?php
$bytes = file_put_contents('compras.txt', "arroz\nfeijão\nleite\n");
var_dump($bytes);
echo file_get_contents('compras.txt');
- file_put_contents(
- A função que grava.
- 'compras.txt',
- 1º argumento: o nome do arquivo. Sem pasta na frente, ele fica na pasta atual.
- "arroz\nfeijão\nleite\n"
- 2º argumento: o texto. Cada
\né uma quebra de linha (por isso aspas duplas; veja Strings). - $bytes =
- A função devolve quantos bytes gravou (ou
falsese falhou). - file_get_contents('compras.txt')
- Lê o arquivo inteiro e devolve o texto, que o
echomostra.
$ cd arq $ php escrever.php int(20) « 20 bytes gravados arroz feijão leite $ cat compras.txt « o arquivo ficou no disco, mesmo depois de o PHP terminar arroz feijão leite
Conte: arroz (5) + feijão (6) + leite (5) + 3 quebras de linha = 19 caracteres. Mas o ã ocupa 2 bytes em UTF-8, então o arquivo tem 20 bytes. A mesma história do strlen com acentos.
Escrever por cima × acrescentar no fim
Cuidado: por padrão, file_put_contents apaga o que havia no arquivo e grava o texto novo. Para acrescentar no fim, passe a "bandeira" (flag) FILE_APPEND ("anexar ao arquivo") como terceiro argumento:
<?php
file_put_contents('compras.txt', "café\n", FILE_APPEND);
file_put_contents('compras.txt', "açúcar\n", FILE_APPEND);
echo file_get_contents('compras.txt');
$ php acrescentar.php arroz feijão leite café « acrescentado açúcar « acrescentado
E sem o FILE_APPEND:
<?php
file_put_contents('compras.txt', "pão\n");
echo file_get_contents('compras.txt');
$ php sobrescrever.php pão « o resto da lista sumiu: o arquivo foi reescrito do zero
Quando o PHP grava por cima, o conteúdo antigo é perdido para sempre: não vai para a lixeira. Antes de testar algo com arquivos importantes, faça uma cópia (copy('dados.txt', 'dados-copia.txt');).
Missão: o programa grava a lista e depois tenta acrescentar café e açúcar, mas a lista começa do zero a cada linha. Conserte as duas últimas gravações para que a lista final tenha os cinco itens.
<?php
file_put_contents('compras.txt', "arroz\nfeijão\nleite\n");
file_put_contents('compras.txt', "café\n");
file_put_contents('compras.txt', "açúcar\n");
echo file_get_contents('compras.txt');
<?php
file_put_contents('compras.txt', "arroz\nfeijão\nleite\n");
file_put_contents('compras.txt', "café\n", FILE_APPEND);
file_put_contents('compras.txt', "açúcar\n", FILE_APPEND);
echo file_get_contents('compras.txt');
Ler linha por linha com file()
Muitas vezes você não quer o texto inteiro, e sim cada linha separada, para contar, filtrar ou mostrar numa lista. A função file() lê o arquivo e devolve um array, com uma linha em cada posição:
<?php
file_put_contents('compras.txt', "arroz\nfeijão\n\nleite\n");
$linhas = file('compras.txt');
var_dump($linhas);
$ php linhas.php
array(4) {
[0]=>
string(6) "arroz
" « a quebra de linha veio junto!
[1]=>
string(8) "feijão
"
[2]=>
string(1) "
" « a linha em branco virou um item
[3]=>
string(6) "leite
"
}
Duas surpresas: cada item termina com a quebra de linha ("arroz\n", por isso o string(6)), e a linha vazia também entrou. Quase sempre você quer o contrário, e para isso existem duas bandeiras, que se combinam com |:
$limpas = file('compras.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
var_dump($limpas);
echo "Itens: " . count($limpas) . "\n";
« (continuação da saída de php linhas.php)
array(3) {
[0]=>
string(5) "arroz"
[1]=>
string(7) "feijão"
[2]=>
string(5) "leite"
}
Itens: 3
| Bandeira | Tradução | Efeito |
|---|---|---|
FILE_IGNORE_NEW_LINES | "ignorar as quebras de linha" | Tira o \n do fim de cada item. |
FILE_SKIP_EMPTY_LINES | "pular as linhas vazias" | Não coloca as linhas em branco no array (só funciona junto com a de cima). |
O | entre elas é o "ou" de bits: um jeito de passar várias bandeiras num argumento só. Você não precisa entender a matemática, só a receita: BANDEIRA_1 | BANDEIRA_2.
O jeito passo a passo: fopen, fgets, fwrite, fclose
file_get_contents e file() carregam o arquivo inteiro na memória. Para arquivos pequenos, perfeito. Para um arquivo de registro com 2 GB, o programa estouraria a memória. O jeito "clássico", herdado da linguagem C, abre o arquivo e lê ou escreve um pedaço por vez:
fopen(file open, "abrir arquivo"): abre e devolve um identificador (um "marcador de página" do caderno).fgets(file get string, "pegar uma linha"): lê a próxima linha. Oufwrite(file write, "escrever"): escreve um texto.fclose(file close, "fechar"): fecha o arquivo e libera o identificador.
<?php
$arquivo = fopen('diario.txt', 'w');
fwrite($arquivo, "16/10: vendi 3 bolos\n");
fwrite($arquivo, "17/10: vendi 5 bolos\n");
fclose($arquivo);
$arquivo = fopen('diario.txt', 'r');
$numero = 1;
while (($linha = fgets($arquivo)) !== false) {
echo $numero . ": " . $linha;
$numero++;
}
fclose($arquivo);
| Linha | O que faz |
|---|---|
$arquivo = fopen('diario.txt', 'w'); | Abre para escrever ('w' = write). Cria o arquivo ou apaga o conteúdo antigo. $arquivo guarda o identificador. |
fwrite($arquivo, "…\n"); | Escreve o texto no ponto onde o "marcador" está, e o marcador anda para depois dele. |
fclose($arquivo); | Fecha. Garante que tudo foi gravado no disco. |
fopen('diario.txt', 'r') | Abre de novo, agora para ler ('r' = read), com o marcador no começo. |
while (($linha = fgets($arquivo)) !== false) | Lê uma linha e guarda em $linha; quando acabar o arquivo, fgets devolve false e o while para. Os parênteses extras fazem a atribuição acontecer antes da comparação. |
echo $numero . ": " . $linha; | Mostra a linha com o número. Sem \n no fim, porque a linha já traz a sua quebra. |
$ php fopen.php 1: 16/10: vendi 3 bolos 2: 17/10: vendi 5 bolos $ cat diario.txt 16/10: vendi 3 bolos 17/10: vendi 5 bolos
!== false e não só while ($linha = fgets($arquivo))?
Uma linha com o texto "0" (sem quebra, a última do arquivo) é considerada "falsa" pelo PHP (veja Booleanos), e o laço pararia antes da hora. Comparar com !== false só para quando o arquivo realmente acabou.
Os modos do fopen
O segundo argumento do fopen diz o que você pretende fazer com o arquivo:
| Modo | Vem de | Lê? | Escreve? | Se não existe | Se já existe |
|---|---|---|---|---|---|
'r' | read | sim | não | Warning, devolve false | começa do início |
'w' | write | não | sim | cria | apaga tudo |
'a' | append | não | sim, no fim | cria | mantém e escreve no fim |
'x' | exclusive | não | sim | cria | Warning File exists, devolve false |
'r+', 'w+', 'a+', 'x+' | O mesmo do modo sem +, mas permitindo ler e escrever. | ||||
O modo 'x' é útil para "crie só se ainda não existir", sem risco de apagar nada:
$ php modos.php « $f = fopen('compras.txt', 'x'); var_dump($f);
Warning: fopen(compras.txt): Failed to open stream: File exists in /home/ana/arq/modos.php on line 2
bool(false)
Qual usar?
| Situação | Use |
|---|---|
| Ler um arquivo pequeno inteiro (um texto, um JSON, um modelo de e-mail) | file_get_contents |
| Ler um arquivo pequeno como lista de linhas | file(…, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) |
| Gravar ou acrescentar um texto | file_put_contents (com FILE_APPEND para acrescentar) |
| Arquivo grande (registros, exportações), ler ou escrever em partes | fopen + fgets/fwrite + fclose |
| CSV (planilhas) | fopen + fgetcsv/fputcsv (aula CSV) |
Missão: o diario.txt (na segunda aba) tem as vendas de três dias. Complete o programa para mostrar cada linha numerada (1: 16/10: …) e, no fim, a linha Total: 3 dias.
<?php
$arquivo = fopen('diario.txt', 'r');
$numero = 0;
// leia as linhas aqui
fclose($arquivo);
16/10: vendi 3 bolos 17/10: vendi 5 bolos 18/10: vendi 2 tortas
<?php
$arquivo = fopen('diario.txt', 'r');
$numero = 0;
while (($linha = fgets($arquivo)) !== false) {
$numero++;
echo $numero . ": " . $linha;
}
fclose($arquivo);
echo "Total: $numero dias\n";
Perguntar antes: existe? é pasta?
Ler um arquivo que não existe dá aviso. Antes, você pode perguntar:
<?php
var_dump(file_exists('compras.txt'));
var_dump(file_exists('receitas.txt'));
var_dump(is_file('compras.txt'));
var_dump(is_dir('compras.txt'));
var_dump(is_dir('/home/ana'));
echo filesize('compras.txt'), " bytes\n";
$ php existe.php bool(true) « compras.txt existe bool(false) « receitas.txt não existe bool(true) « compras.txt é um arquivo comum bool(false) « …e não é uma pasta bool(true) « /home/ana é uma pasta 21 bytes
| Função | Pergunta |
|---|---|
file_exists($c) | "Existe algo com esse nome?" (arquivo ou pasta) |
is_file($c) | "É um arquivo comum?" |
is_dir($c) | "É uma pasta (directory)?" |
is_readable($c) / is_writable($c) | "Posso ler?" / "Posso escrever?" |
filesize($c) | Tamanho em bytes. |
filemtime($c) | Quando foi modificado (um timestamp; veja Datas e Horas). |
Pastas: criar, listar, apagar
A Ana quer guardar cada pedido num arquivo, dentro de uma pasta pedidos:
<?php
if (!is_dir('pedidos')) {
mkdir('pedidos');
echo "Pasta criada.\n";
}
file_put_contents('pedidos/001.txt', "2 bolos de cenoura\n");
file_put_contents('pedidos/002.txt', "1 torta de limão\n");
print_r(scandir('pedidos'));
$ php pastas.php
Pasta criada.
Array
(
[0] => .
[1] => ..
[2] => 001.txt
[3] => 002.txt
)
- mkdir('pedidos')
- make directory, "criar pasta" (o mesmo nome do comando do terminal).
- scandir('pedidos')
- scan directory, "varrer a pasta": devolve um array com os nomes, em ordem alfabética.
- . e ..
- Toda pasta tem essas duas entradas especiais:
.é a própria pasta e..é a pasta de cima. Quase sempre você vai querer tirá-las.
Para listar só os arquivos de verdade, tire o . e o .. com array_diff, ou use glob, que aceita curingas como no terminal:
<?php
foreach (array_diff(scandir('pedidos'), ['.', '..']) as $nome) {
echo "$nome\n";
}
print_r(glob('pedidos/*.txt'));
$ php glob.php
001.txt
002.txt
Array
(
[0] => pedidos/001.txt « glob devolve o caminho junto
[1] => pedidos/002.txt
)
Pastas dentro de pastas
mkdir só cria uma pasta por vez, e reclama se ela já existir:
<?php
mkdir('pedidos');
mkdir('fotos/2026/outubro');
var_dump(mkdir('fotos/2026/outubro', 0755, true));
$ php mkdir-erro.php Warning: mkdir(): File exists in /home/ana/arq/mkdir-erro.php on line 2 Warning: mkdir(): No such file or directory in /home/ana/arq/mkdir-erro.php on line 3 bool(true) $ ls -R fotos fotos: 2026 fotos/2026: outubro fotos/2026/outubro:
A linha 2 falhou porque pedidos já existia (File exists). A linha 3 falhou porque fotos e fotos/2026 não existiam (No such file or directory). A linha 4 funcionou graças ao terceiro argumento, true ("recursivo"), que cria todas as pastas do caminho, como o mkdir -p do terminal. O 0755 é a permissão das pastas novas, no mesmo formato do chmod (o 0 na frente é obrigatório: é um número em octal).
Apagar e mover
<?php
unlink('pedidos/001.txt');
print_r(scandir('pedidos'));
unlink('pedidos/001.txt');
$ php apagar.php
Array
(
[0] => .
[1] => ..
[2] => 002.txt « o 001.txt sumiu
)
Warning: unlink(pedidos/001.txt): No such file or directory in /home/ana/arq/apagar.php on line 4
unlink ("desvincular") é o nome histórico de "apagar arquivo", vindo do Unix. Para apagar uma pasta, use rmdir, que só funciona com a pasta vazia:
$ php rmdir.php « rmdir('pedidos'); com o 002.txt ainda lá dentro
Warning: rmdir(pedidos): Directory not empty in /home/ana/arq/rmdir.php on line 2
E para copiar, mover e desmontar caminhos:
<?php
copy('diario.txt', 'diario-backup.txt');
rename('diario-backup.txt', 'pedidos/diario-antigo.txt');
print_r(scandir('pedidos'));
$caminho = '/home/ana/arq/pedidos/002.txt';
echo basename($caminho), "\n";
echo dirname($caminho), "\n";
print_r(pathinfo($caminho));
echo realpath('pedidos/../diario.txt'), "\n";
$ php outros.php
Array
(
[0] => .
[1] => ..
[2] => 002.txt
[3] => diario-antigo.txt « copiado e depois movido (rename também move)
)
002.txt « basename: só o nome
/home/ana/arq/pedidos « dirname: só a pasta
Array
(
[dirname] => /home/ana/arq/pedidos
[basename] => 002.txt
[extension] => txt
[filename] => 002
)
/home/ana/arq/diario.txt « realpath: o caminho completo, sem ".."
Caminhos: relativos a quê?
Um nome como 'compras.txt' ou 'pedidos/001.txt' é um caminho relativo: o PHP o procura a partir da pasta atual do programa, que é a pasta de onde ele foi chamado, e não a pasta onde o arquivo .php está. Veja:
<?php echo getcwd(), "\n"; echo __DIR__, "\n"; file_put_contents(__DIR__ . '/registro.txt', "ok\n"); var_dump(file_exists(__DIR__ . '/registro.txt'));
$ cd ~ $ php arq/dir.php /home/ana « getcwd(): a pasta atual (de onde a Ana chamou) /home/ana/arq « __DIR__: a pasta do arquivo dir.php bool(true)
Se o programa tivesse gravado só 'registro.txt', o arquivo iria parar em /home/ana, e não ao lado do script. Num site, a "pasta atual" depende do servidor. Por isso, a regra é a mesma da aula include e require: para arquivos que acompanham o seu programa, monte o caminho com __DIR__ . '/nome.txt'.
Um mural de recados (modo web)
Juntando tudo: uma página com um formulário onde os clientes deixam recados, guardados num arquivo de texto, um por linha. Cada vez que alguém envia, a página acrescenta uma linha e mostra todas.
<?php
$arquivo = __DIR__ . '/recados.txt';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$nome = trim($_POST['nome'] ?? '');
$recado = trim($_POST['recado'] ?? '');
if ($nome !== '' && $recado !== '') {
$linha = str_replace("\n", ' ', "$nome: $recado") . "\n";
file_put_contents($arquivo, $linha, FILE_APPEND | LOCK_EX);
}
}
$recados = file_exists($arquivo)
? file($arquivo, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)
: [];
?>
<h1>Mural de recados da Lojinha</h1>
<form method="post">
<input name="nome" placeholder="Seu nome">
<input name="recado" placeholder="Seu recado">
<button>Enviar</button>
</form>
<ul>
<?php foreach ($recados as $r): ?>
<li><?= htmlspecialchars($r) ?></li>
<?php endforeach; ?>
</ul>
<p><?= count($recados) ?> recado(s).</p>
| Trecho | Por quê |
|---|---|
str_replace("\n", ' ', …) | Um recado com várias linhas quebraria a regra "um recado por linha". Trocamos as quebras por espaços. |
FILE_APPEND | LOCK_EX | Acrescenta no fim e tranca o arquivo (exclusive lock) durante a gravação: se dois clientes enviarem no mesmo instante, um espera o outro, e as linhas não se misturam. |
file_exists(…) ? file(…) : [] | Na primeira visita o arquivo ainda não existe: em vez de um Warning, começamos com uma lista vazia. |
htmlspecialchars($r) | O recado foi escrito por um visitante. Sem escapar, um <script> no recado rodaria no navegador de todo mundo (veja XSS). |
A Ana testou com o servidor embutido e o curl, mandando dois recados (o primeiro com HTML de propósito):
$ curl -s -X POST --data "nome=Bia&recado=Adorei o bolo de <b>cenoura</b>!" localhost:8000/ <h1>Mural de recados da Lojinha</h1> <form method="post"> <input name="nome" placeholder="Seu nome"> <input name="recado" placeholder="Seu recado"> <button>Enviar</button> </form> <ul> <li>Bia: Adorei o bolo de <b>cenoura</b>!</li> « o HTML virou texto inofensivo </ul> <p>1 recado(s).</p> $ curl -s -X POST --data "nome=Caio&recado=Quero encomendar" localhost:8000/ | tail -6 </form> <ul> <li>Bia: Adorei o bolo de <b>cenoura</b>!</li> <li>Caio: Quero encomendar</li> </ul> <p>2 recado(s).</p> $ cat recados.txt Bia: Adorei o bolo de <b>cenoura</b>! « no arquivo, o texto fica original Caio: Quero encomendar
Missão: o mural já tem um recado da Ana (aba recados.txt), e a caixa abre enviando um recado da Bia. Mas o programa apaga os recados antigos a cada envio e não mostra a lista. Conserte a gravação (acrescentar, não substituir) e complete a parte que lê o arquivo em $recados. Depois, deixe outros recados pela aba Resultado.
<?php
$arquivo = __DIR__ . '/recados.txt';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$nome = trim($_POST['nome'] ?? '');
$recado = trim($_POST['recado'] ?? '');
if ($nome !== '' && $recado !== '') {
$linha = str_replace("\n", ' ', "$nome: $recado") . "\n";
file_put_contents($arquivo, $linha);
}
}
$recados = []; // leia as linhas do arquivo aqui
?>
<h1>Mural de recados da Lojinha</h1>
<form method="post">
<input name="nome" placeholder="Seu nome">
<input name="recado" placeholder="Seu recado">
<button>Enviar</button>
</form>
<ul>
<?php foreach ($recados as $r): ?>
<li><?= htmlspecialchars($r) ?></li>
<?php endforeach; ?>
</ul>
<p><?= count($recados) ?> recado(s).</p>
Ana: Bem-vindos ao mural!
<?php
$arquivo = __DIR__ . '/recados.txt';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$nome = trim($_POST['nome'] ?? '');
$recado = trim($_POST['recado'] ?? '');
if ($nome !== '' && $recado !== '') {
$linha = str_replace("\n", ' ', "$nome: $recado") . "\n";
file_put_contents($arquivo, $linha, FILE_APPEND | LOCK_EX);
}
}
$recados = file_exists($arquivo)
? file($arquivo, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)
: [];
?>
<h1>Mural de recados da Lojinha</h1>
<form method="post">
<input name="nome" placeholder="Seu nome">
<input name="recado" placeholder="Seu recado">
<button>Enviar</button>
</form>
<ul>
<?php foreach ($recados as $r): ?>
<li><?= htmlspecialchars($r) ?></li>
<?php endforeach; ?>
</ul>
<p><?= count($recados) ?> recado(s).</p>
Quando dá errado
$ php nao-existe.php « $texto = file_get_contents('receitas.txt'); var_dump($texto); …
Warning: file_get_contents(receitas.txt): Failed to open stream: No such file or directory in /home/ana/arq/nao-existe.php on line 2
bool(false)
Warning: fopen(receitas.txt): Failed to open stream: No such file or directory in /home/ana/arq/nao-existe.php on line 4
bool(false)
O que significa: "falhou ao abrir: arquivo ou diretório inexistente". O PHP avisa e devolve false no lugar do texto (ou do identificador).
Como consertar: confira o nome (maiúsculas contam), a pasta atual (getcwd()) e use __DIR__. Se o arquivo pode legitimamente não existir, pergunte antes com file_exists.
$ php fgets-false.php « $f = fopen('receitas.txt', 'r'); echo fgets($f);
Warning: fopen(receitas.txt): Failed to open stream: No such file or directory in /home/ana/arq/fgets-false.php on line 2
Fatal error: Uncaught TypeError: fgets(): Argument #1 ($stream) must be of type resource, false given in /home/ana/arq/fgets-false.php:3
Stack trace:
#0 /home/ana/arq/fgets-false.php(3): fgets(false)
#1 {main}
thrown in /home/ana/arq/fgets-false.php on line 3
O que significa: o fopen devolveu false (primeiro aviso), e o programa passou esse false para o fgets, que esperava um arquivo aberto (um resource). O erro de verdade é o da linha 2; o da linha 3 é consequência.
Como consertar: confira o resultado do fopen antes de usar: if ($f === false) { echo "Não consegui abrir.\n"; exit(1); }. Na aula de exceções você vai ver formas mais elegantes.
A Ana tirou a permissão de escrita de um arquivo (chmod 444, veja as permissões no Guia Bash) e tentou gravar nele:
$ chmod 444 trancado.txt
$ ls -l trancado.txt
-r--r--r-- 1 ana ana 9 out 16 20:47 trancado.txt
$ php permissao.php « $ok = file_put_contents('trancado.txt', "novo texto\n"); var_dump($ok);
Warning: file_put_contents(trancado.txt): Failed to open stream: Permission denied in /home/ana/arq/permissao.php on line 2
bool(false)
O que significa: "permissão negada". O arquivo existe, mas o usuário que roda o PHP não pode escrever nele (ou na pasta).
Como consertar: no seu computador, ajuste as permissões (chmod u+w trancado.txt). Num servidor, o PHP roda como outro usuário (no Ubuntu/Debian, www-data), e é esse usuário que precisa poder escrever na pasta de dados. Nunca resolva com chmod 777: isso deixa qualquer um no servidor alterar os arquivos.
Warning: mkdir(): File exists in /home/ana/arq/mkdir-erro.php on line 2
O que significa: a pasta já existe.
Como consertar: pergunte antes: if (!is_dir('pedidos')) { mkdir('pedidos'); }.
Referência
| Função | O que faz | Devolve |
|---|---|---|
file_get_contents($c) | Lê o arquivo inteiro | string ou false |
file_put_contents($c, $texto, $flags) | Grava (por cima, ou no fim com FILE_APPEND; LOCK_EX tranca) | bytes gravados ou false |
file($c, $flags) | Lê como array de linhas | array ou false |
fopen($c, $modo) | Abre (r w a x, com +) | identificador ou false |
fgets($f) | Lê a próxima linha | string ou false no fim |
fwrite($f, $texto) | Escreve | bytes ou false |
feof($f) | "Chegou ao fim?" (end of file) | bool |
fclose($f) | Fecha | bool |
file_exists, is_file, is_dir | Perguntas sobre o caminho | bool |
filesize, filemtime | Tamanho, data de modificação | int |
mkdir($c, 0755, true) | Cria pasta (com true: o caminho todo) | bool |
scandir($c) / glob('*.txt') | Lista uma pasta / por curinga | array |
unlink($c) / rmdir($c) | Apaga arquivo / pasta vazia | bool |
copy($de, $para) / rename($de, $para) | Copia / renomeia ou move | bool |
basename, dirname, pathinfo, realpath | Desmontam e arrumam caminhos | string / array |
getcwd(), __DIR__ | Pasta atual / pasta do script | string |
Exercícios
1. Acrescentar
Complete para acrescentar uma linha ao fim do arquivo, sem apagar o que já existe:
2. Modo de leitura
Complete o modo do fopen para apenas ler:
3. Pastas aninhadas
Complete para criar fotos/2026/outubro de uma vez, mesmo que fotos não exista:
4. O que file('lista.txt') devolve, sem bandeiras?
5. O que acontece com fopen('dados.txt', 'w') se dados.txt já tem conteúdo?
6. O site da Ana mostra Permission denied ao gravar recados.txt no servidor. O que fazer?
Missão final: crie a pasta pedidos (só se ela não existir), grave três arquivos (001.txt, 002.txt, 003.txt, cada um com um pedido) e depois liste os nomes, um por linha, sem o . e o ... Termine com a linha 3 pedidos, calculada com count. Rode duas vezes: não pode aparecer nenhum Warning.
<?php $pasta = __DIR__ . '/pedidos';
<?php
$pasta = __DIR__ . '/pedidos';
if (!is_dir($pasta)) {
mkdir($pasta);
}
file_put_contents("$pasta/001.txt", "2 bolos de cenoura\n");
file_put_contents("$pasta/002.txt", "1 torta de limão\n");
file_put_contents("$pasta/003.txt", "12 brigadeiros\n");
$nomes = array_diff(scandir($pasta), ['.', '..']);
foreach ($nomes as $nome) {
echo "$nome\n";
}
echo count($nomes) . " pedidos\n";
Resumo
file_put_contentsgrava (por cima!) efile_get_contentslê o arquivo inteiro.FILE_APPENDacrescenta no fim.file()devolve as linhas num array; useFILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES.- Para arquivos grandes:
fopen→fgets/fwrite→fclose, comwhile (($linha = fgets($f)) !== false). - Pergunte antes com
file_exists/is_dir; crie pastas commkdir(truepara o caminho todo), liste comscandir/glob, apague comunlink/rmdir. - Falhas viram
Warning+false: confira o retorno antes de usar. - Caminhos relativos partem da pasta atual; use
__DIR__. - Texto de visitante gravado em arquivo: escape com
htmlspecialcharsna hora de mostrar.
Próxima aula: CSV, o formato das planilhas, lido e gravado linha a linha.