DEV Community

Cover image for How to create a file watcher with PHP and the Elementary Framework
Nana Axel
Nana Axel

Posted on • Updated on

How to create a file watcher with PHP and the Elementary Framework

Introduction

Welcome everyone to this second How-To about the Elementary Framework (for those who have missed the first How-To, check it here).

In this article we will talk about the creation of a file watcher, a console app which will watch files in a directory and report to us any changes made to these files (deletion, creation, modification), written in the PHP language using FireFS, a part of my framework.

Creating a file watcher it's just a possibility of FireFS between much more others.

Prerequisites

Before start, make sure you have:

  • A PHP IDE or editor: You can download Visual Studio Code, it's a free and powerful code editor which can support many languages (including PHP).
  • Composer: Composer is a dependencies manager for PHP projects. You can download it at https://getcomposer.org/

Part 1 - Preparing the project

The first thing we have to do is to create our new project. Create a new folder with the name you want, and open a terminal into it.

FireFS is a composer package, so we need first to prepare our project to use composer. In the terminal you previuously opened, type:

composer init

This will initialize our project with composer support. Follow the initialization process to the end.

Now, in the same terminal, we can install FireFS with the command:

composer require elementaryframework/fire-fs

And wait the process finish, this will download the source code of the FireFS project and install it in your own. When the installation succeed, type again:

composer dump-autoload -o

This will generate an optimized autoloader file (useful for production). For a normal autoload file, just omit the -o switch.

Once FireFS is installed, we can now create the command line tool to watch our files. Create a file named watch inside your project folder and insert into it:

#!/usr/bin/env php

<?php

// Require composer autoload file
require "./vendor/autoload.php";

// Print a message to the console
print "Hello world, this is a file watcher!";

What we are doing ?

  • We first require the autoloader file from composer
  • We print a message to the console output

To test if everything is working, just type in the terminal (while the working directory is the same as our project):

php watch

The console will print the text "Hello world, this is a file watcher!" before exit.

Note that the file name is watch (without any extension), and not watch.php

Part 2 - Our file watcher

Building a file watcher with FireFS is very easy, we just have to create a new FileSystemWatcher object, follow the build pattern and start it, easy, right?

The FireFS object

In FireFS, instances of the FireFS class represent a file system, and manage every files and folders in the given root directory. When creating a file watcher we have first to create a file system:

// We use the FireFS class
use ElementaryFramework\FireFS\FireFS;

// We create a new file system on the current directory
$fs = new FireFS();

This will create a file system at the same path than our watch file (to change the root path, just define your prefered path as the first parameter of the FireFS class constructor).

The watched folder

Now we have to create the folder which will be watched. We can let our console app do it itself by using the great FireFS API:

// Check if the directory to watch exists
if (!$fs->exists("files_to_watch")) {
    // If not, create the directory
    $fs->mkdir("files_to_watch");
}

This will create the directory files_to_watch only if it not exists at each run of our file watcher.

The IFileSystemListener object

Before enjoying our file watcher, we have to create a class implementing the IFileSystemListener interface. This class is used by the watcher to execute specific actions following the watch event (create, delete, update).

// We use the IFileSystemWatcher interface
use ElementaryFramework\FireFS\Listener\IFileSystemListener;

// We use the FileSystemEvent class
use ElementaryFramework\FireFS\Events\FileSystemEvent;

// Our listener
class WatcherListener implements IFileSystemListener
{
    /**
     * Action executed on any event.
     * The returned boolean will define if the
     * specific event handler (onCreated, onModified, onDeleted)
     * have to be called after this call.
     */
    public function onAny(FileSystemEvent $event): bool
    {
        $eventType = $event->getEventType();
        $date = date("d/m/Y H:i:s");

        if ($eventType === FileSystemEvent::EVENT_UNKNOWN) {
            return true;
        }

        switch ($eventType) {
            case FileSystemEvent::EVENT_CREATE:
                print "{$date}  -  [Created]  {$event->getPath()}\n";
                break;

            case FileSystemEvent::EVENT_MODIFY:
                print "{$date}  -  [Updated]  {$event->getPath()}\n";
                break;

            case FileSystemEvent::EVENT_DELETE:
                print "{$date}  -  [Deleted]  {$event->getPath()}\n";
                break;
        }

        return false;
    }

    /**
     * Action executed when a file/folder is created.
     */
    public function onCreated(FileSystemEvent $event)
    { }

    /**
     * Action executed when a file/folder is updated.
     */
    public function onModified(FileSystemEvent $event)
    { }

    /**
     * Action executed when a file/folder is deleted.
     */
    public function onDeleted(FileSystemEvent $event)
    { }
}

The FileSystemWatcher object

Once we have a file system object and we know the directory (or the file) we want to watch, we can create the file watcher:

// We use the FileSystemWatcher class
use ElementaryFramework\FireFS\Watcher\FileSystemWatcher;

// Create the file watcher
$watcher = new FileSystemWatcher($fs);

The next step is to configure our watcher. The configuration is done by calling some methods:

  • setListener(IFileSystemListener): Defines the IFileSystemListener instance used to execute specific actions on each files updates ;
  • setPath(string): Defines the path of directory/file to watch ;
  • setRecursive(bool): Defines if the watcher will watch for files recursively (works only if the watched entity is a directory) ;
  • addPattern(Regex): Add a files-to-watch pattern ;
  • addExcludePattern(Regex): Add a files-to-exclude pattern ;
  • setPattern(array): Set an array of files-to-watch patterns. This will overwrite any existing pattern ;
  • setExcludePattern(array): Set an array of files-to-exclude patterns. This will overwrite any existing pattern ;
  • setWatchInterval(int): Set the interval in milliseconds in which the watcher will process a watch event.

So we will build our watcher like this:

$watcher
    ->setListener(new WatcherListener)
    ->setRecursive(true)
    ->setPath("./files_to_watch")
    ->setWatchInterval(250)
    ->build(); // It's important to call build to validate the configuration

Important to know: The FileSystemWatcher class have some default exclude patterns, check them here

At this time, everything is set! Now the last thing to do is to start the watcher:

// Start the file watcher
$watcher->start();

The complete watch file

We just have finished to create our file watcher, there is the complete file content:

#!/usr/bin/env php

<?php

// Require composer autoloader
require_once __DIR__ . '/vendor/autoload.php';

// We use the FireFS class
use ElementaryFramework\FireFS\FireFS;

// We use the IFileSystemWatcher interface
use ElementaryFramework\FireFS\Listener\IFileSystemListener;

// We use the FileSystemEvent class
use ElementaryFramework\FireFS\Events\FileSystemEvent;

// We use the FileSystemWatcher class
use ElementaryFramework\FireFS\Watcher\FileSystemWatcher;

// We create a new file system on the current directory
$fs = new FireFS();

// Check if the directory to watch exists
if (!$fs->exists("files_to_watch")) {
    // If not, create the directory
    $fs->mkdir("files_to_watch");
}

// Our listener
class WatcherListener implements IFileSystemListener
{
    /**
     * Action executed on any event.
     * The returned boolean will define if the
     * specific event handler (onCreated, onModified, onDeleted)
     * have to be called after this call.
     */
    public function onAny(FileSystemEvent $event): bool
    {
        $eventType = $event->getEventType();
        $date = date("d/m/Y H:i:s");

        if ($eventType === FileSystemEvent::EVENT_UNKNOWN) {
            return true;
        }

        switch ($eventType) {
            case FileSystemEvent::EVENT_CREATE:
                print "{$date}  -  [Created]  {$event->getPath()}\n";
                break;

            case FileSystemEvent::EVENT_MODIFY:
                print "{$date}  -  [Updated]  {$event->getPath()}\n";
                break;

            case FileSystemEvent::EVENT_DELETE:
                print "{$date}  -  [Deleted]  {$event->getPath()}\n";
                break;
        }

        return false;
    }

    /**
     * Action executed when a file/folder is created.
     */
    public function onCreated(FileSystemEvent $event)
    { }

    /**
     * Action executed when a file/folder is updated.
     */
    public function onModified(FileSystemEvent $event)
    { }

    /**
     * Action executed when a file/folder is deleted.
     */
    public function onDeleted(FileSystemEvent $event)
    { }
}

// Create the file watcher
$watcher = new FileSystemWatcher($fs);

$watcher
    ->setListener(new WatcherListener)
    ->setPath("./files_to_watch")
    ->setWatchInterval(250)
    ->build(); // It's important to call build to validate the configuration

// Start the file watcher
$watcher->start();

Now run this file using the command php watch, a new folder files_to_watch is directly created and the console wait for files changes. Try to create, delete or edit files inside the files_to_watch folder and you will be directly notified for these actions inside the console!

php watch

26/07/2019 15:53:20  -  [Created]  D:\AliensGroup\Hyde\hyde-cli\files_to_watch\composer.json
26/07/2019 15:54:24  -  [Created]  D:\AliensGroup\Hyde\hyde-cli\files_to_watch\composer.lock
26/07/2019 15:54:24  -  [Created]  D:\AliensGroup\Hyde\hyde-cli\files_to_watch\hyde
26/07/2019 15:54:29  -  [Deleted]  D:\AliensGroup\Hyde\hyde-cli\files_to_watch\composer.lock
26/07/2019 15:54:47  -  [Updated]  D:\AliensGroup\Hyde\hyde-cli\files_to_watch\hyde

Conclusion

With this article, we have learn How to create a file watcher with PHP and the Elementary Framework. Using the FireFS module of the framework, we have seen steps by steps how it's very easy to implement a functionality like this. Now with the knowledge you have you can create more than a simple event reporting app, from crons on your webserver, to your own Jekyll PHP edition ;-), you have everything you need to go further.

What next?

GitHub logo ElementaryFramework / FireFS

Easily manage your filesystem through PHP

FireFS Logo

FireFS

downloads downloads downloads downloads

Manage your file system easily, through php

FireFS is a library allowing you to write/read/delete files and folders of your file system, safely and easily.

It can be used for web applications as well for console applications, without any requirements.

Example

<?php
use ElementaryFramework\FireFS\FireFS
// Create a new file system instance at the given path
$fs = new FireFS("./app"); // /root/var/www/htdocs/app/
// Check if the path "/root/var/www/htdocs/app/images/" exists
if ($fs->exists("images")) {
    // Change the working directory to the images folder
    $fs->setWorkingDirectory("./images");

    // Create a new file in the working directory
    $fs->mkfile("./logo.png"); // /root/var/www/htdocs/app/images/logo.png

    // Read file from the file system root path
    $logo = $fs->read("logo.png"); // /root/var/www/htdocs/app/logo.png

    // Write into the created file
    $

Discussion (0)