Appending to a file

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
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.

  1. <?php
  2. // Get data from the URL.
  3. $cutestDog = $_GET['name'];
  4. $rating = $_GET['cuteness'];
  5. // Log.
  6. $logEntry = "Cutest dog: $cutestDog Rating: $rating\n";
  7. file_put_contents(__DIR__ . '/dog-log.txt', $logEntry, FILE_APPEND);
  8. ?><!DOCTYPE html>
  9. <html lang="en">
  10.     <head>
  11.         <meta charset="UTF-8">
  12.         <title>Cutest Dog</title>
  13.         <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  14.     </head>
  15.     <body>
  16.         <h1>Cutest dog</h1>
  17.         <p>The results are in!</p>
  18.         <p>Cutest dog: <?php print $cutestDog; ?></p>
  19.         <p>Rating: <?php print $rating; ?> out of 10.</p>
  20.     </body>
  21. </html>
  22.  
  23. Line 6 makes a log message. Line 7 writes it.
  24.  
  25. pause.
Reflect

What is the \n on line 6 for?

If you were logged in as a student, the lesson would pause here, and you'd be asked to type in a response. If you want to try that out, ask for an account on this site.
Ethan
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:

Files before

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:

Files after

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:

Log file contents

Here's what I saw after refreshing the browser:

After refresh

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:

  1. <?php
  2. // Get data from the URL.
  3. $cutestDog = $_GET['name'];
  4. $rating = $_GET['cuteness'];
  5. // Log.
  6. $filePath = __DIR__ . '/dog-log.txt';
  7. if ( file_exists($filePath) && filesize($filePath) > 10000) {
  8.     header('Location: log-file-size-warning.php');
  9.     exit();
  10. }
  11. $logEntry = "Cutest dog: $cutestDog Rating: $rating\n";
  12. file_put_contents($filePath, $logEntry, FILE_APPEND);
  13. ?><!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:

Warning

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.