Form validation.pattern for !URLs

Hi there,

I get a lot of spam mails through the public available forms. I use the honypot field but looks like spam-bots are too clever to get trapped.
Also I want to avoid using google captcha as long as there are other autmated solutons.

After some search for best-practice I came across two ideas for detecting form spam:

  1. The first one uses a hidden field with a timestamp and and compares the submitted timestamp with the current time. if the delta is below a certain time it´s likley that there was no human involved. I guess this is something which has to be implemented in the plugin itself.

  2. Spam-bots want to share URLs. All of the spam-mails i have in the inbox contain an URL in the message-field. But it doesn´t make sense to write about URLs in my forms, so I thought about adding a validation.pattern that checks for URL-strings. Basically checking for “http://” would be enough.
    For this approach I need some help. How would a validation pattern look like, that is falsey when a URL is included?

And does it work to have

validation.required: false

and also a functional validation.pattern?

Thanks and all the best
mirac

so far, this dosn´t work:

pattern: '/^((?!http[s]?:\/\/).)*$/m'

matches true to everything.

I’ve used this one before to check on urls:

“/\b(?:(?:https?|ftp)://|www.)[-a-z0-9+&@#/%?=~|!:,.;]*[-a-z0-9+&@#/%=~|]/i”

Edit out the ftp part and it should work perfectly fine for you :slight_smile: (I think :wink: )

Did you find a resolution to this problem @miraculli ?

I face something similar with text field validation

@daubneyi, I needed a solution myself for my own ContactForm plugin because someone was having a blast last night filling my mailbox which a few thousand of spam messages…

The solution mentioned above, seems to be failing when surrounding the pattern with a /. And without the /s, the pattern will fail when ‘message’ contains newlines.

So here is a rough abstract of the solution I was working on. It requires a custom plugin, but isn’t that difficult to create. It allows you to add as many patterns and messages as you like.

  • Create a plugin using $ bin/plugin devtools new-plugin
    Let’s assume you named it ‘nospam’.
  • In ‘/user/plugins/nospam/nospam.yaml’ add the following:
    enabled: true
    fields:
      name: []
      email: []
      phone: []
      message:
        - pattern: '/<br\/?>/i'
          message: 'HTML is not allowed'
        - pattern: '/https?:\/\//i'
          message: 'URL is not allowed'
    onSpam: notify   # die|notify (default)
    
  • In file ‘/user/plugins/nospam/nospam.php’:
    • Alter function ‘onPluginsInitialized’ into:

      public function onPluginsInitialized(): void
      {
          // Don't proceed if we are in the admin plugin
          if ($this->isAdmin()) {
              return;
          }
      
          // Enable the main events we are interested in
          $this->enable([
              // Put your main events here
              'onFormPrepareValidation' => ['onFormPrepareValidation', 0],
          ]);
      }
      
    • Create a new function to validate the fields

      public function onFormPrepareValidation(Event $event)
      {
          /** @var Form */
          $form = $event['form'];
          $values = $form->value();
          $fields = array_keys($form->getFields());
          $onSpam = $this->config->get("plugins.nospam.onSpam", 'notify');
      
          $messages = [];
      
          foreach($fields as $field) {
              $patterns = $this->config->get("plugins.nospam.fields.$field", []);
      
              foreach($patterns as $pattern) {
                  if (preg_match($pattern['pattern'], $values[$field]) === 1) {
                      if ($onSpam === 'die') {
                          die();
                      }
      
                      if (!isset($messages[$field])) {
                          $messages[$field] = [];
                      }
                      $messages[$field][] = "Field '$field': {$pattern['message']}";
                  }
              }
          }
      
          if (count($messages) > 0) {
              $exception = new ValidationException('');
              $exception->setMessages($messages);
      
              throw $exception; 
          }
      }
      
    • Result:
      Untitled

    • Notes:

      • Multiple notifications per field.
      • Multiple validation checks per field.
      • onSpam: notify: show validation message in page.
      • onSpam: die: stop processing when spam detected.
      • nospam.yaml: Only add fields that need testing for spam.
      • Simpler regex: no negative lookahead required.
    • Todo:

      • Add blueprint for easy form in Admin.
3 Likes

Here is what I have used to screen for links. It’s been tested on a few sites for a few years and I can’t remember how all of it works!

'^((?!https?:\/\/)(?:\R|.))*$'

I hope it’s useful rather than confusing and unwelcome :confused:

1 Like