loading...

Laravel validation rules — file exists, MAC address & equals value.

mattkingshott profile image Matt Kingshott 👨🏻‍💻 Originally published at itnext.io on ・4 min read

Image courtesy of Unsplash

Laravel validation rules — File exists, MAC addresses & is equal to a value

In this new series, we’ll be exploring the concept of custom validation rules in Laravel and how they can assist you. I’m posting an article each day with a new rule you can use in your projects. The rules are also part of a package.

In this post, we’ll be creating a rule which confirms a user has specified a path to a file that exists, a rule to confirm that a supplied MAC address is valid, and we’ll look at a rule that verifies the user has supplied an accepted value.

If you’re new to this topic, check out the first article in the series.

Promotion

I’ve recently released Pulse — a friendly, affordable server and site monitoring service designed specifically for developers. It includes all the usual hardware monitors, custom service monitors, alerting via various notification channels, logs, as well as full API support. Take a look… https://pulse.alphametric.co

Server and Site Monitoring with Pulse

Rule #1 — Mac Addresses

Let’s begin by writing the logic necessary to ensure that the user has provided a valid MAC address. Per the conventions, the following must be true:

  1. Six octets (upper or lowercase) must be provided.
  2. An octet must consist of either a numeric digit or an A-F letter.
  3. Each octet must be separated by colons or dashes.

The easiest way to enforce these requirements is with a regular expression:

public function passes($attribute, $value)
{
    return preg\_match(
        "/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/", $value
    );
}

Next, we’ll need to write an error message to respond with when the user has supplied a value which is not a valid MAC address:

public function message()
{
    return 'The :attribute must be a valid MAC address;
}

As before, we’ll write a quick unit test to confirm that the rule works correctly and rejects values that are not MAC addresses:

/\*\* @test \*/
public function the\_mac\_address\_rule\_can\_be\_validated()
{
    $rule = ['address' => [new MacAddress]];

    $this->assertTrue(validator(['address' => '3D:F2:C9:A6:B3:4F'], $rule)->passes());

    $this->assertTrue(validator(['address' => '3D-F2-C9-A6-B3-4F'], $rule)->passes());

    $this->assertFalse(validator(['address' => '00:00:00:00:00:00:00'], $rule)->passes());
}

Rule #2 — File Exists

Next, we’ll allow a user to supply a path to a file and verify that the file does indeed exist. To do this, we’ll need to accept two parameters:

  1. The disk the file should exist on. This disk should be configured using the filesystems.php file in your application configuration.
  2. The path to the file itself.

We’ll then make use of the Storage facade to perform the check, while also performing some initial sanitisation of the user input to eliminate any extra slashes in the file path:

public function passes($attribute, $value)
{
    $path = rtrim($this->parameters[1] ?? '', '/');
    $file = ltrim($value, '/');

    return Storage::disk($this->parameters[0])
                  ->exists("$path/$file");
}

As before, we’ll need to write an error message to respond with:

public function message()
{
    return 'The file specified for :attribute does not exist';
}

And finally, include a unit test:

/\*\* @test \*/
public function the\_file\_exists\_rule\_can\_be\_validated()
{
    $rule = ['file' => [new FileExists('local', '/')]];

    $this->assertTrue(validator(['file' => 'real.txt'], $rule)->passes());

    $this->assertFalse(validator(['file' => 'fake.txt'], $rule)->passes());
}

Note that the actual unit test is more involved as steps have to be taken to set the configuration, create test files etc. See the class within the package.

Rule #3 — Equals

This last rule is more of an example of “semantic sugar”. Technically, you can achieve the same result using Laravel’s native in rule and supplying a single value instead of many comma-separated options.

However, the word “in” implies that multiple values are valid, while perhaps only one value is truly valid given a particular scenario. In this situation, I think using “equals” is more semantically correct / easier to understand.

As you would imagine, the logic is simple. We have a single parameter that we compare to the supplied value and ensure it is the same:

public function passes($attribute, $value)
{
    return $value === $this->parameters[0];
}

We’ll also include the error response:

public function message()
{
    return 'The :attribute must be set to "' . 
           $this->parameters[0] . '"'
}

And the unit test:

/\*\* @test \*/
public function the\_equals\_rule\_can\_be\_validated()
{
    $rule = ['value' => [new Equals('2')]];

    $this->assertFalse(validator(['value' => '0'], $rule)->passes());

    $this->assertFalse(validator(['value' => '1'], $rule)->passes());

    $this->assertTrue(validator(['value' => '2'], $rule)->passes());
}

Wrapping Up

You can see the classes and pull them into your projects by visiting the repo on Github: https://github.com/alphametric/laravel-validation-rules

I have additional validation rules that I intend to share with you in the coming days, so be sure to follow me for those articles. If you’re interested, you can also follow me on Twitter to see everything I’m up to.

Happy coding!


Posted on by:

mattkingshott profile

Matt Kingshott 👨🏻‍💻

@mattkingshott

Founder. Developer. Writer. Lunatic. Created Pulse, IodineJS, Axiom, and more. #PHP #Laravel #Vue #TailwindCSS

Discussion

markdown guide