Write to a log file with PHP

More...

As I caught myself in process of writing PHP "log" function several times I have finally decided to create a simple Logging PHP class. After Logging class initialization, first call of lwrite method will open log file implicitly and write line to the file. Every other lwrite will use already opened file pointer until closing file with lclose. It is always a good idea to close a file when it's over. This should prevent file from corruption and overhead in closing file is negligible.

Before you read further, I also wrote a post how to Log PHP errors to the separate file, if you are looking for such information.

How to use Logging class:

// Logging class initialization
$log = new Logging();

// set path and name of log file (optional)
$log->lfile('/tmp/mylog.txt');

// write message to the log file
$log->lwrite('Test message1');
$log->lwrite('Test message2');
$log->lwrite('Test message3');

// close log file
$log->lclose();

Output in mylog.txt will look like:

[10/Jun/2012:10:36:19] (test) Test message1
[10/Jun/2012:10:36:19] (test) Test message2
[10/Jun/2012:10:36:19] (test) Test message3

Logging class source code:

/**
 * Logging class:
 * - contains lfile, lwrite and lclose public methods
 * - lfile sets path and name of log file
 * - lwrite writes message to the log file (and implicitly opens log file)
 * - lclose closes log file
 * - first call of lwrite method will open log file implicitly
 * - message is written with the following format: [d/M/Y:H:i:s] (script name) message
 */
class Logging {
    // declare log file and file pointer as private properties
    private $log_file, $fp;
    // set log file (path and name)
    public function lfile($path) {
        $this->log_file = $path;
    }
    // write message to the log file
    public function lwrite($message) {
        // if file pointer doesn't exist, then open log file
        if (!is_resource($this->fp)) {
            $this->lopen();
        }
        // define script name
        $script_name = pathinfo($_SERVER['PHP_SELF'], PATHINFO_FILENAME);
        // define current time and suppress E_WARNING if using the system TZ settings
        // (don't forget to set the INI setting date.timezone)
        $time = @date('[d/M/Y:H:i:s]');
        // write current time, script name and message to the log file
        fwrite($this->fp, "$time ($script_name) $message" . PHP_EOL);
    }
    // close log file (it's always a good idea to close a file when you're done with it)
    public function lclose() {
        fclose($this->fp);
    }
    // open log file (private method)
    private function lopen() {
        // in case of Windows set default log file
        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
            $log_file_default = 'c:/php/logfile.txt';
        }
        // set default log file for Linux and other systems
        else {
            $log_file_default = '/tmp/logfile.txt';
        }
        // define log file from lfile method or use previously set default
        $lfile = $this->log_file ? $this->log_file : $log_file_default;
        // open log file for writing only and place file pointer at the end of the file
        // (if the file does not exist, try to create it)
        $this->fp = fopen($lfile, 'a') or exit("Can't open $lfile!");
    }
}

For PHP prior to version 5.2.0 you will have to replace or change line with built-in PHP function pathinfo() because PATHINFO_FILENAME constant was added in PHP 5.2.0

// for PHP 5.2.0+
$script_name = pathinfo($_SERVER['PHP_SELF'], PATHINFO_FILENAME);

// for PHP before version 5.2.0
$script_name = basename($_SERVER['PHP_SELF']);
$script_name = substr($script_name, 0, -4); // php extension and dot are not needed

If you want to send a message to the PHP's system logger, please see the error_log PHP command.

This entry was posted on January 14, 2009 and is filed under PHP

Related posts

39 Responses to Write to a log file with PHP

  1. bhowe says:

    Shouldn't you always implicitly close file handles or am I just paranoid ( or blind) . Nice little class though Ill add it to my arsenal.

  2. Mathou says:

    Nice, Thanks.

  3. devidas says:

    This is nice code I was implement in my project. Thanx so much

  4. Kay says:

    Very useful, but would give better output for windows with each message on a new line by adding " /r" in the fwrite() function. that is:

    fwrite($this->fp, "$time ($script_name) $message\r\n");
    

    EXAMPLE OUTPUT:

    16:03:15 (preview) Test message
    16:03:35 (preview) Test message
    16:03:50 (preview) Test message
    

    I used it thanks

  5. dbunic says:

    @bhowe - Logging class now contains lclose public method - thank you.

    @Kay - You are right. If Logging class is used on Windows then CR and LF shoud be used to break the line. Linux/Unix uses only LF. I added "\r\n" to the comment above fwrite line.

    Info: From this moment, source code of the Logging class can be downloaded from the Download link below post title.

  6. Hello, first thing first: thanks for the class!

    About what @Kay wrote, can I suggest to change the code

    fwrite($this->fp, "$time ($script_name) $message\n");
    

    with this:

    if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
        fwrite($this->fp, "$time ($script_name) $message\r\n");
    }
    else {
        fwrite($this->fp, "$time ($script_name) $message\n");
    }

    It can save some time to a lot of people!
    Have a nice day!

  7. dbunic says:

    @Daniele Alano - Thank you for PHP code. Definition of newline character is now included in Logging class. Windows users shoud not have problems any more.
    Cheers!

  8. Really nice and simple.
    Self documenting code.
    I like it.

  9. Trejder says:

    Great script! :] Only one, small notice. You take a special care of line ending, in case of running your class under Windows. But you forgot to do the same in case of default file name. You force /tmp/logfile.log when file name is not provided, but this path is invalid on Windows.

    Also, I'm not sure, if your class should force adding current date to a file name. This should be handled by devloper using your class.

    Big thanks anyway!

  10. dbunic says:

    @Trejder - Your suggestions are welcome. I made changes and now PHP class takes care for default log file on Windows. Date from log file name is also removed. Thanks!

  11. IT_Architect says:

    Ooooo, close! The only thing missing is rotation. If you write a log, there has to be a way to limit its size.

  12. IT_Architect says:

    It's working great! I just made a few changes:
    1. I added a optional property to set a max size for the log file, with a default of 1 Meg:

    private $log_file, $log_size, $nl, $fp;
        // set log file (path and name)
        public function lfile($path, $size=1) {
            $this->log_file = $path;
            $this->log_size = $size *(1024*1024); // Megs to bytes
        }
    
    // define log file from lfile method or use previously set default
    $lfile = $this->log_file ? $this->log_file : $log_file_default;
    if (file_exists($lfile)) {
        if (filesize($lfile) > $this->log_size) {
            $this->fp = fopen($lfile, 'w') or die("can't open file file!");
            fclose($this->fp);
            unlink($lfile);
          }
    }
    // open log file for writing only and place file pointer at the end of the file
    // (if the file does not exist, try to create it)
    $this->fp = fopen($lfile, 'a') or exit("Can't open file!");
    

    The new call with the optional parameter becomes:

    $log->lfile($filename, $log_size);
    

    2. Formatted the time stamp to be like standard log files to include the date.

    $time = @date('[D M d G:i:s Y]');
    

    That's it!

  13. Confined says:

    Could you use PHP_EOL for a new line instead?

  14. dbunic says:

    @IT_Architect - Thank you for posting modification for limiting file size. This will be useful for others. Your suggestion about adding date to the timestamp format is applied to Logging class.

    @Confined - PHP_EOL is used now instead of newline definition. Class now looks simpler - thanks!

  15. JrBriones says:

    Very nice class!
    thank you

  16. Thanks. It was helpfull

  17. Philipp says:
    if (!$this->fp) {
    

    in lwrite should be:

    if (!is_resource($this->fp)) {
    
  18. Thank you very much for putting up this file and for free.

    It worked for me and it was very useful!

  19. dbunic says:

    @Philipp - Logging class is updated with is_resource() function. Thank you!