Validate sprintf format from input field with regex - php

I have an input field where both regular text and sprintf tags can be entered.
Example: some text here. %1$s done %2$d times
How do I validate the sprintf parts so its not possible them wrong like %$1s ?
The text is utf-8 and as far as I know regex only match latin-1 characters.
www.regular-expressions.info does not list /u anywhere, which I think is used to tell that string is unicode.
Is the best way to just search the whole input field string for % or $ and if either found then apply the regex to validate the sprintf parts ?
I think the regex would be: /%\d\$(s|d|u|f)/u

I originally used Gumbo's regex to parse sprintf directives, but I immediately ran into a problem when trying to parse something like %1.2f. I ended up going back to PHP's sprintf manual and wrote the regex according to its rules. By far I'm not a regex expert, so I'm not sure if this is the cleanest way to write it:
/%(?:\d+\$)?[+-]?(?:[ 0]|'.{1})?-?\d*(?:\.\d+)?[bcdeEufFgGosxX]/

The UTF-8 modifier is not necessary unless you use UTF-8 in your pattern. And beside that the sprintf format is more complex, try the following
/%(?:\d+\$)?[dfsu]/
This would match both the %s and %1$s format.
But if you want to check every occurrence of % and whether a valid sprintf() format is following, regular expressions would not be a good choice. A sequential parser would be better.

This is what I ended up with, and its working.
// Always use server validation even if you have JS validation
if (!isset($_POST['input']) || empty($_POST['input'])) {
// Do stuff
} else {
$matches = explode(' ',$_POST['input']);
$validInput = true;
foreach ($matches as $m) {
// Check if a slice contains %$[number] as it indicates a sprintf format
if (preg_match('/[%\d\$]+/',$m) > 0) {
// Match found. Now check if its a valid sprintf format
if ($validInput === false || preg_match('/^%(?:\d+\$)?[dfsu]$/u',$m)===0) { // no match found
$validInput = false;
break; // Invalid sprintf format found. Abort
}
}
}
if ($validInput === false) {
// Do stuff when input is NOT valid
}
}
Thank you Gumbo for the regex pattern that matches both with and without order marking.
Edit: I realized that searching for % is wrong, since nothing will be checked if its forgotten/omitted. Above is new code.
"$validInput === false ||" can be omitted in the last if-statement, but I included it for completeness.

Related

PHP preg_match regular expression for find date in string

I try to make system that can detect date in some string, here is the code :
$string = "02/04/16 10:08:42";
$pattern = "/\<(0?[1-9]|[12][0-9]|3[01])\/\.- \/\.- \d{2}\>/";
$found = preg_match($pattern, $string);
if ($found) {
echo ('The pattern matches the string');
} else {
echo ('No match');
}
The result i found is "No Match", i don't think that i used correct regex for the pattern. Can somebody tell me what i must to do to fix this code
First of all, remove all gibberish from the pattern. This is the part you'll need to work on:
(/0?[1-9]|[12][0-9]|3[01]/)
(As you said, you need the date only, not the datetime).
The main problem with the pattern, that you are using the logical OR operators (|) at the delimiters. If the delimiters are slashes, then you need to replace the tube characters with escaped slashes (/). Note that you need to escape them, because the parser will not take them as control characters. Like this: \/.
Now, you need to solve some logical tasks here, to match the numbers correctly and you're good to go.
(I'm not gonna solve the homework for you :) )
These articles will help you to solve the problem tough:
Character classes
Repetition opetors
Special characters
Pipe character (alternation operator)
Good luck!
In your comment you say you are looking for yyyy, but the example says yy.
I made a code for yy because that is what you gave us, you can easily change the 2 to a 4 and it's for yyyy.
preg_match("/((0|1|2|3)[0-9])\/\d{2}\/\d{2}/", $string, $output_array);
Echo $output_array[1]; // date
Edit:
If you use this pattern it will match the time too, thus make it harder to match wrong.
((0|1|2|3)[0-9])/\d{2}/\d{2}\s+\d{2}:\d{2}:\d{2}
http://www.phpliveregex.com/p/fjP
Edit2:
Also, you can skip one line of code.
You first preg_match to $found and then do an if $found.
This works too:
If(preg_match($pattern, $string, $found))}{
Echo $found[1];
}Else{
Echo "nothing found";
}
With pattern and string as refered to above.
As you can see the found variable is in the preg_match as the output, thus if there is a match the if will be true.

Regex fomatting and design for a query

I'm having a some trouble formatting my regular expression for my PHP code using preg_match().
I have a simple string usually looking like this:
"q?=%23asdf".
I want my regular expression to only pass true if the string begins with "q?=%23" and there is a character at the end of the 3. So far one of the problems I have had is that the ? is being pulled up by the regex so doing something like
^q?=23 doesn't work. I am also having problems with contiguous searching in Regex expressions (because I can't figure out how to search after the 3).
So for clarification: "q?=%23asd" should PASS and "q?=%23" should FAIL
I'm no good with Regex so sorry if this seems like a beginner question and thanks in advance.
Just use a lookahead to check whether the character following 3 is an alphabet or not,
^q\?=%23(?=[a-zA-Z])
Add . instead of [A-Za-z] only if you want to check for any character following 3,
^q\?=%23(?=.)
Code would be,
$theregex = '~^q\?=%23(?=[a-z])~i';
if (preg_match($theregex, $yourstring)) {
// Yes! It matches!
}
else { // nah, no luck...
}
So the requirement is: Start with q?=%23, followed by at least one [a-z], the pattern could look like:
$pattern = '/^q\?=%23[a-z]+/i';
Used i (PCRE_CASELESS) modifier. Also see example at regex101.
$string = "q?=%23asdf";
var_dump(figureOut($string));
function figureOut($string){
if(strpos($string, 'q?=%23') == 0){
if(strlen($string) > 6){
return true;
}else{ return false;}
}
}

Match multiple characters without repetion on a regular expression

I'm using PHP's PCRE, and there is one bit of the regex I can't seem to do. I have a character class with 5 characters [adjxz] which can appear or not, in any order, after a token (|) on the string. They all can appear, but they can only each appear once. So for example:
*|ad - is valid
*|dxa - is valid
*|da - is valid
*|a - is valid
*|aaj - is *not* valid
*|adjxz - is valid
*|addjxz - is *not* valid
Any idea how I can do it? a simple [adjxz]+, or even [adjxz]{1,5} do not work as they allow repetition. Since the order does not matter also, I can't do /a?d?j?x?z?/, so I'm at a loss.
Perhaps using a lookahead combined with a backreference like this:
\|(?![adjxz]*([adjxz])[adjxz]*\1)[adjxz]{1,5}
demonstration
If you know these characters are followed by something else, e.g. whitespace you can simplify this to:
\|(?!\S*(\S)\S*\1)[adjxz]{1,5}
I think you should break this in 2 steps:
A regex to check for unexpected characters
A simple PHP check for duplicated characters
function strIsValid($str) {
if (!preg_match('/^\*|([adjxz]+)$/', $str, $matches)) {
return false;
}
return strlen($matches[1]) === count(array_unique(str_split($matches[1])));
}
I suggest using reverse logic where you match the unwanted case using this pattern
\|.*?([adjxz])(?=.*\1)
Demo

How to validate a regex with PHP

I want to be able to validate a user's inputted regex, to check if it's valid or not. First thing I found with PHP's filter_var with the FILTER_VALIDATE_REGEXP constant but that doesn't do what I want since it must pass a regex to the options but I'm not regex'ing against anything so basically it's just checking the regex validity.
But you get the idea, how do I validate a user's inputted regex (that matches against nothing).
Example of validating, in simple words:
$user_inputted_regex = $_POST['regex']; // e.g. /([a-z]+)\..*([0-9]{2})/i
if(is_valid_regex($user_inputted_regex))
{
// The regex was valid
}
else
{
// The regex was invalid
}
Examples of validation:
/[[0-9]/i // invalid
//(.*)/ // invalid
/(.*)-(.*)-(.*)/ // valid
/([a-z]+)-([0-9_]+)/i // valid
Here's an idea (demo):
function is_valid_regex($pattern)
{
return is_int(#preg_match($pattern, ''));
}
preg_match() returns the number of times pattern matches. That will be
either 0 times (no match) or 1 time because preg_match() will stop
searching after the first match.
preg_match() returns FALSE if an error occurred.
And to get the reason why the pattern isn't valid, use preg_last_error.
You would need to write your own function to validate a regex. You can validate it so far as to say whether it contains illegal characters or bad form, but there is no way to test that it is a working expression. For that you would need to create a solution.
But then you do realize there really is no such thing as an invalid regex. A regex is performance based. It either matches or it doesn't and that is dependent upon the subject of the test--even if the expression or its results are seemingly meaningless.
In other words, you can only test a regular expression for valid syntax...and that can be nearly anything!

PHP Regex Functions

I am trying to validate form input data using PHP's preg_match function. I am a little confused of how to use it. If I want to validate say an alphanumeric string, I would use ^[0-9a-zA-Z ]+$ as the first parameter and the string we're validating as the second one. But how would I use preg_match to tell if it's valid or not? Would I do this:
if(preg_match("^[0-9a-zA-Z ]+$", $_POST['display_name'])){
"String is valid";
} else {
"String is not valid";
}
Or the other way around? I am currently using the if not preg_match if statement but it's returning false for some reason... I know this is probably an easy answer, but I cannot figure this out.
FALSE return from a preg_match indicates an error
you need to delimit your regex (see the leading and trailing / you can use other characters too
if (preg_match("/^[0-9a-zA-Z ]+$/", $_POST['display_name'])) {
You need add the delimiters of your pattern, like this:
preg_match("/^[0-9a-zA-Z ]+$/", $_POST['display_name'])

Categories