Regex not validating consistently - php

I'm experiencing an usual problem and I can't seem to nail down the cause. I'm working on server side validation for a number of fields on a signup form on a site. This is the block of PHP:
if ('phone-name' == $tag->name) {
$value = $_POST[$tag->name];
if (!preg_match('/\+([0-9])([ .-]*\d){7,12}/', $value)) {
$result->invalidate($tag, "You must enter a valid number: $value is not valid");
}
}
The regex I am using should only allow the user to input:
the "+" sign
spaces, dots and hyphens
and any number from 0 to 9
However when I run the following tests I get these results:
TEST 1: INVALID INPUT
+3588<script>alert(1)</script>
TEST 2: VALID INPUT
+35388888888<script>alert(1)</script>
Is there something I am missing here? How come the regex works for TEST 2 and not for TEST 1? Any help is much appreciated.
Thanks

Because your regex is matching the number at the beginning of the string. You could use ^$ to match string length (beginning and end), truncate the string first, use strip_tags, etc.
Example:
http://www.regexr.com/3bmfm
^\+([0-9])([ .-]*\d){7,12}$
Remove the ^ and $ from beginning and end of pattern to see it match the second line.

Because you specified how many times a given pattern should be repeated by {7,12}.

Related

PHP Regex Regular Expressions preg_match() only allow digits with commas

I've asked and it was answered but now, after years, it doesn't work.
I've even tried online regex validators. Not sure what is going on.
Version: PHP 7.0.30 on 64Bit OS
The string should only allow digits with commas.
No commas in the beginning or end.
Spaces between commas is ok but I'd rather not allow it.
The following isn't passing
My regex is:
$DateInvoicedIDs = "1031,453,808,387,111,342,962,706,251,442,362,858,950,738,310,288,99,665,1023,30,894,112,132,148,347,895,382,94,766,683,276,1104,658,34,348,235,786,769,2";
$reg = '/[0-9\s]+(,[0-9\s]+)*[0-9]$/';
if ( preg_match($reg, $DateInvoicedIDs) ) {
echo = $DateInvoicedIDs;
} else { echo "false"; }
I'm using preg_match and getting false.
Any idea?
Test your string and pattern # https://regex101.com/r/3TVmOv/1
When that loads, you will see that there is no match highlighted.
Then add a digit to the end of your string and Whalla! This is because (,[0-9\s]+)* is matching the final 2 and [0-9]$ cannot be satisfied because another digit is required.
If I understand your logic/requirements, I think I'd use ~^\d+(?:\s*,\s*\d+)*$~
This improves the validation because it doesn't allow a mixture of digits and spaces between commas like: 2, 3 4 56, 72 I don't think you want spaces in your comma-separated numerical values.
Pattern Demo
Code: (Demo)
$DateInvoicedIDs = "1031,453,808,387,111,342,962,706,251,442,362,858,950,738,310,288,99,665,1023,30,894,112,132,148,347,895,382,94,766,683,276,1104,658,34,348,235,786,769,2";
$reg = '/^\d+(?:\s*,\s*\d+)*$/';
if (preg_match($reg, $DateInvoicedIDs)) {
echo $DateInvoicedIDs;
} else {
echo "false";
}
It is not matching because of the last [0-9] in your regex. The * in (,[0-9\s]+)* is a greedy match which means that it is consuming all commas followed by digits in your string. There is nothing left after to match against the last [0-9].
So you probably want to reduce your regex to '/[0-9\s]+(,[0-9\s]+)*$/.
The last part of your regex [0-9]$ is what's causing it to fail:
[0-9\s]+ is matching the first number only 1031,
(,[0-9\s]+)* is covering everything until ,2 because it's a single number right after a comma which is what it's looking for
Then [0-9]$ is trying to find one more number but it can't
If the last number is a double-digit number, i.e. ,25 instead of 2, then the that second part (,[0-9\s]+)* would be satisfied because it found at least one number and [0-9]$ would match the next number which is 5 (https://regex101.com/r/0XbHsw/1)
Adding ? for that last part would solve the problem: [0-9\s]+(,[0-9\s]+)*[0-9]?$

Unique regex for name validation

I want to check is the name valid with regex PHP, but i need a unique regex that allows:
Letters (upper and lowercase)
Spaces (max 2)
But there can't be a space after space..
For example:
Name -> Dennis Unge Shishic (valid)
Name -> Denis(space)(space) (not valid)
Hope you guys understand me, thank you :)
First, it's worth mentioning that having such restrictive rules for the names of persons is a very bad idea. However, if you must, a simple character class like this will limit you to just uppercase and lowercase English letters:
[A-Za-z]
To match one or more, you need to add a + after it. So, this will match the first part of the name:
[A-Za-z]+
To capture a second name, you just need to do the same thing preceded by a space, so something like this will capture two names:
[A-Za-z]+ [A-Za-z]+
To make the second name optional, you need to surround it by parentheses and add a ? after it, like this:
[A-Za-z]+( [A-Za-z]+)?
And to add a third name, you just need to do it again:
[A-Za-z]+( [A-Za-z]+)? [A-Za-z]+
Or, you could specify that the latter names can repeat between 1 and 2 times, like this:
[A-Za-z]+( [A-Za-z]+){1,2}
To make the resulting code easy to understand and maintain, you could use two Regex. One checking (by requiring it to be true) that only the allowed characters are used ^[a-zA-Z ]+$ and then another one, checking (by requiring it to be false) that there are no two (or more) adjacent spaces ( ){2,}
Try following working code:
Change input to whatever you want to test and see correct validation result printed
<?php
$input_line = "Abhishek Gupta";
preg_match("/[a-zA-Z ]+/", $input_line, $nameMatch);
preg_match("/\s{2,}/", $input_line, $multiSpace);
var_dump($nameMatch);
var_dump($multiSpace);
if(count($nameMatch)>0){
if(count($multiSpace)>0){
echo "Invalid Name Multispace";
}
else{
echo "Valid Name";
}
}
else{
echo "Invalid Name";
}
?>
A regex for one to three words consisting of only Unicode letters in PHP looks like
/^\p{L}+(?:\h\p{L}+){1,2}\z/u
Description:
^ - string start
\p{L}+ - one or more Unicode letters
(?:\h\p{L}+){1,2} - one or two sequences of a horizontal whitespace followed with one or more Unicode letters
\z - end of string, even disallowing trailing newline that a dollar anchor allows.

Get first part of UK postcode only

I'm trying to get the first part of a UK postcode from a string that may have only the first part of the postcode or the full postcode in it. I'm struggling to make it work. I've got it working if the full postcode is entered by using a look-ahead, but I can't seem to make the look-ahead optional, so if only the first part of the postcode is entered it is matched.
My regex so far is ([A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]([0-9ABEHMNPRV-Y])?)|[0-9][A-HJKPS-UW])(?=( ?[0-9][ABD-HJLNP-UW-Z]{2})))
I've got several postcodes that must match and these are the results using the above regex:
A10EA - Should match and does
A1 - Should match but doesn't
A10 0EA - Should match and does
A10 - Should match but doesn't
BH18 1AE - Should match and does
BH18AE - Should match and does
EC1M 6HJ - Should match and does
EC1M - Should match but doesn't
Z10 2EV - Shouldn't match and doesn't
QE3 6DA - Shouldn't match but matches E3 6DA
Can someone please help me solve this issue?
The RegEx I've been working from is the official one from the post office:
/^(GIR ?0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]([0-9ABEHMNPRV-Y])?)|[0-9][A-HJKPS-UW]) ?[0-9][ABD-HJLNP-UW-Z]{2})$/i
Before anyone flags this as a duplicate of PHP Find first part of UK postcode when full or part can be entered, it's not. The answer for that question doesn't work, see my comment to the answer.
According this wiki page the post code always ends in 'digit letter letter', that would be a regex pattern of \d\w\w$. Now we know how to spot what the end is, we just want to capture the rest.
A pattern like (\S*)\s*\d\w\w$ will work. That will capture the first half, and ensure that you do not get the last 'digit letter letter part. It will capture the first part by getting anything not white space, ie only letters and digits.
To fully explain this, the brackets () is what we are capturing. \S says 'any one non white space character, with \S*being all that we can get. so (\S*) captures everything up to a space character, but will capture everything if the user doesn't enter one. The full regex I provided will also try to capture 'any white space, one digit, two letters, end of string' which will ensure that AA999AA is split into AA99 and 9AA.
I've also just noticed though that your question states you might not actually have that second part. I think you could get around that by checking the string length. If you trim white space and the length is less than 5 characters, you must only have the first part, so no need for any regex.
disclaimer this will not work for Anguillan postcodes. To support their postcodes as well, I think (\S*)\s*(?:\d\w\w|-\d{4})$ would work.
I've been looking at this the wrong way. I want to get the first part of the postcode and remove the second part if present, so why not validate the postcode first, then check for an end and strip it if necessary.
I'm already validating the postcode, this is code I already had:
$validate = Validation::factory(array('postcode' => $postcode));
$validate->rule('postcode', 'not_empty');
$validate->rule('postcode', 'regex', array(':value', '/^(GIR ?(0AA)?|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]([0-9ABEHMNPRV-Y])?)|[0-9][A-HJKPS-UW]) ?([0-9][ABD-HJLNP-UW-Z]{2})?)$/i'));
if ( ! $validate->check())
{
$postcode = '';
}
So now I've added in this after it:
if ($postcode)
{
$short_postcode = $postcode;
// Check for an end section and then if present, remove it
if (preg_match('/ ?([0-9])[ABD-HJLNP-UW-Z]{2})$/i', $postcode, $match, PREG_OFFSET_CAPTURE))
{
$short_postcode = substr($postcode, 0, $match[0][1]);
}
}
and this leaves me with just the first part of the postcode, which is what I wanted. This Eval.in shows it working for all the examples in my question.

PHP - preg_match()

Alright, so I want the user to be able to enter every character from A-Z and every number from 0-9, but I don't want them entering "special characters".
Code:
if (preg_match("/^[a-zA-Z0-9]$/", $user_name)) {
#Stuff
}
How is it possible for it to check all of the characters given, and then check if those were matched? I've tried preg_match_all(), but I didn't honestly understand much of it.
Like if a user entered "FaiL65Mal", I want it to allow it and move on. But if they enter "Fail{]^7(,", I want it to appear with an error.
You just need a quantifier in your regex:
Zero or more characters *:
/^[a-zA-Z0-9]*$/
One or more characters +:
/^[a-zA-Z0-9]+$/
Your regex as is will only match a string with exactly one character that is either a letter or number. You want one of the above options for zero or more or one or more, depending on if you want to allow or reject the empty string.
Your regular expression needs to be changed to
/^[a-zA-Z0-9]{1,8}$/
For usernames between 1 and 8 characters. Just adjust the 8 to the appropriate number and perhaps the 1.
Currently your expression matches one character
Please keep in mid that preg_match() and other preg_*() functions aren't reliable because they return either 0 or false on fail, so a simple if won't throw on error.
Consider using T-Regx:
if (pattern(('^[a-zA-Z0-9]{1,8}$')->matches($input))
{
// Matches! :)
}

Validating form data using regex

I'm newest and happy to be here in Stackoverflow. I am following this website since a long time.
I have an input/text field. (e.g. "Insert your name")
The script starts the following controls when the user sends data:
1) Control whether the field is empty or not.
2) Control whether the field goes over maximum characters allowed.
3) Control whether the field contain a wrong matched preg_match regex. (e.g. it contains numbers instead of only letters - without symbols and accents -).
The question is: why if i put this characters "w/", the script doesn't make the control? And it seems like the string bypass controls?
Hello to all guys and sorry if I'm late with the answer (and also for the non-code posted ^^).
Now, talking about my problem. I checked that the problem is on ONLY if I work offline (I use EasyPhp 5.3.6.1). Otherwise the regEx tested online is ok.
This is the code I use to obtain only what I said above:
if (!preg_match('/^[a-zA-Z]+[ ]?[a-zA-Z]+$/', $name)) {
echo "Error";
}
As you can see, this code match:
A string that start (and finish) with only letters;
A string with only 0 or 1 empty space (for persons who has two name, i.e.: Anna Maria);
...right?!
(Please correct me if I am wrong)
Thanks to all!
Wart
My reading of the requirements is
Only letters (upper or lower) can be provided.
Something must be provided (i.e. a non-zero length string).
There is a maximum length.
The code below checks this in a very simple manner and just echos any errors it finds; you probably want to do something more useful when you detect an error.
<?php
$max = 10;
$string = 'w/';
// Check only letters; the regex searches for anything that isn't a plain letter
if (preg_match('/[^a-zA-Z]/', $string)){
echo 'only letters are allowed';
}
// Check a value is provided
$len = strlen($string);
if ($len == 0) {
echo 'you must provide a value';
}
// Check the string is long to long
if ($len > $max) {
echo 'the value cannot be longer than ' . $max;
}
You can also try this:
if (preg_match('/^[a-z0-9]{1,12}/im', $subject)) {
\\ match
}
The above will only match similar to #genesis' post, but will only match if the $subject is between and including 1 - 12 characters long. The regex is also case insensitive.
It works fine.
<?php
$string = '\with';
if (preg_match('~[^0-9a-z]~i', $string)){
echo "only a-Z0-9 is allowed"; //true
}
http://sandbox.phpcode.eu/g/18535/3
You have to make sure you don't put user input into your regex, because that would mean you'll probably check something wrong.

Categories