Append only
In business web apps, you append data to log files, that is, add data to the end. You don't read them, delete them, or anything else. You use other tools, like Excel and a VBA program, to do that.
So, we'll only talk about appending in this course.
Appending in PHP
The function file_put_contents()
will do the job. You call it like this:
- file_put_contents(filepath, data, flags);
In VBA, you'd open the file, write to it, and close. PHP is simpler. It handles the deets for you.
Appending can be as simple as:
- file_put_contents('log-file.txt', 'Rosie is the best dog!', FILE_APPEND);
Adela
What folder would the log file be in? In VBA, we used ThisWorkbook.Path
, to put the file in the same folder as the worksheet. What about PHP?
Ooo, good question, Adela. For now, use __DIR__
, like this:
- file_put_contents(__DIR__ . '/log-file.txt', 'Rosie is the best dog!', FILE_APPEND);
__DIR__
is the PHP for ThisWorkbook.Path
. It's the folder of the PHP page that's running. So if the file_put_contents()
call is in the file my-page.php
, then __DIR__
will be the folder where my-page.php
is.
This isn't good practice. Later, you'll learn a better way.
Cutest dog log
Here's a program what shows the cutest dog, with logging code added.
- <?php
- // Get data from the URL.
- $cutestDog = $_GET['name'];
- $rating = $_GET['cuteness'];
- // Log.
- $logEntry = "Cutest dog: $cutestDog Rating: $rating\n";
- file_put_contents(__DIR__ . '/dog-log.txt', $logEntry, FILE_APPEND);
- ?><!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Cutest Dog</title>
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
- </head>
- <body>
- <h1>Cutest dog</h1>
- <p>The results are in!</p>
- <p>Cutest dog: <?php print $cutestDog; ?></p>
- <p>Rating: <?php print $rating; ?> out of 10.</p>
- </body>
- </html>
- Line 6 makes a log message. Line 7 writes it.
- pause.
What is the \n
on line 6 for?
Ethan
That adds a new line, like hitting Enter. Makes sure each log entry is on a separate line.
Exactly!
Let's try it. I put the code in a file called cutest-dog.php
. Here's what the server looked like before I ran the program:
To run the program, I went to the URL http://localhost:8080/web-apps-course/logging/appending/cutest-dog/cutest-dog.php?name=Rosie&cuteness=12
.
Here's what the files looked like then:
When I ran the program, file_put_contents()
didn't find dog-log.txt
, so it created the file, before appending the data.
Here's the contents of the log file:
Here's what I saw after refreshing the browser:
Each time the page runs, it adds to the log file.
Preventing log file size attack
As is, the code allows a hack attack. The log file keeps growing. If a hacker runs the program a zillion times, the log file could eat the server's disk space.
You can prevent that by testing the size of the log file, before writing to it. Check this out:
- <?php
- // Get data from the URL.
- $cutestDog = $_GET['name'];
- $rating = $_GET['cuteness'];
- // Log.
- $filePath = __DIR__ . '/dog-log.txt';
- if ( file_exists($filePath) && filesize($filePath) > 10000) {
- header('Location: log-file-size-warning.php');
- exit();
- }
- $logEntry = "Cutest dog: $cutestDog Rating: $rating\n";
- file_put_contents($filePath, $logEntry, FILE_APPEND);
- ?><!DOCTYPE html>
Line 6 puts the file path into a variable. We're going to use the file path a few times, so putting it in a variable makes things easier. Easy is good.
Line 7 checks the size of the log file. Remember that the file might not exist, if the page is being run for the first time. So the size check makes sense only if the log file exists. file_exists($filePath)
takes care of that. It returns true if the file exists, false if not.
filesize()
returns the file size. filesize($filePath) > 10000
compares the file size to some large number. Actually, 10,000 isn't very big. It might be more like 10,000,000 in a real app.
OK, what do we do if the log file is too big? This code redirects the browser to a different URL:
- header('Location: log-file-size-warning.php');
- exit();
Redirection works only if nothing else has been output already. If we put the header()
after any HTML has been output, it won't work. So it has to go in the top chunk, before <!DOCTYPE html>
.
exit()
stops the program. Like End
in VBA. It's needed, otherwise the program would continue, and write to the log file anyway.
log-file-size-warning.php
is a simple page:
You could do other things, like send an email alert to someone.
Job interview
"We learned how to protect audit logs from log file size attacks" sounds good in a job interview.