I need to check for a form input value to be a positive integer (not just an integer), and I noticed another snippet using the code below:
$i = $user_input_value;
if (!is_numeric($i) || $i < 1 || $i != round($i)) {
return TRUE;
}
I was wondering if there's any advantage to using the three checks above, instead of just doing something like so:
$i = $user_input_value;
if (!is_int($i) && $i < 1) {
return TRUE;
}
Not sure why there's no suggestion to use filter_var on this. I know it's an old thread, but maybe it will help someone out (after all, I ended up here, right?).
$filter_options = array(
'options' => array( 'min_range' => 0)
);
if( filter_var( $i, FILTER_VALIDATE_INT, $filter_options ) !== FALSE) {
...
}
You could also add a maximum value as well.
$filter_options = array(
'options' => array( 'min_range' => 0,
'max_range' => 100 )
);
Learn more about filters.
the difference between your two code snippets is that is_numeric($i) also returns true if $i is a numeric string, but is_int($i) only returns true if $i is an integer and not if $i is an integer string. That is why you should use the first code snippet if you also want to return true if $i is an integer string (e.g. if $i == "19" and not $i == 19).
See these references for more information:
php is_numeric function
php is_int function
The best way for checking for positive integers when the variable can be INTEGER or STRING representing the integer:
if ((is_int($value) || ctype_digit($value)) && (int)$value > 0 ) { // int }
is_int() will return true if the value type is integer. ctype_digit() will return true if the type is string but the value of the string is an integer.
The difference between this check and is_numeric() is that is_numeric() will return true even for the values that represent numbers that are not integers (e.g. "+0.123").
It's definitely heading towards the land of micro-optimisation, but hey: the code I'm working on chews through millions of items every day and it's Friday. So I did a little bit of experimenting...
for ($i = 0; $i < 1000000; $i++) {
// Option 1: simple casting/equivalence testing
if ((int) $value == $value && $value > 0) { ... }
// Option 2: using is_int() and ctype_digit(). Note that ctype_digit implicitly rejects negative values!
if ((is_int($value) && $value > 0) || ctype_digit($value)) { ... }
// Option 3: regular expressions
if (preg_match('/^\d+$/', $value)) { ... }
}
I then ran the above tests for both integer and string values
Option 1: simple casting/equivalence testing
Integer: 0.3s
String: 0.4s
Option 2: using is_int() and ctype_digit()
Integer: 0.9s
String: 1.45s
Option 3: regular expressions
Integer: 1.83s
String: 1.60s
Perhaps unsurprisingly, option 1 is by far the quickest, since there's no function calls, just casting. It's also worth noting that unlike the other methods, option 1 treats the string-float-integer value "5.0" as an integer:
$valList = array(5, '5', '5.0', -5, '-5', 'fred');
foreach ($valList as $value) {
if ((int) $value == $value && $value > 0) {
print "Yes: " . var_export($value, true) . " is a positive integer\n";
} else {
print "No: " . var_export($value, true) . " is not a positive integer\n";
}
}
Yes: 5 is a positive integer
Yes: '5' is a positive integer
Yes: '5.0' is a positive integer
No: -5 is not a positive integer
No: '-5' is not a positive integer
No: 'fred' is not a positive integer
Whether or not that's a good thing for your particular use-case is left as an exercise for the reader...
The other best way to check a Integer number is using regular expression. You can use the following code to check Integer value. It will false for float values.
if(preg_match('/^\d+$/',$i)) {
// valid input.
} else {
// invalid input.
}
It's better if you can check whether $i > 0 too.
preg_match('{^[0-9]*$}',$string))
and if you want to limit the length:
preg_match('{^[0-9]{1,3}$}',$string)) //minimum of 1 max of 3
So pisitive int with a max length of 6:
if(preg_match('{^[0-9]{1,6}$}',$string)) && $string >= 0)
You don't really need to use all three check and if you want a positive integer you might want to do the opposite of what is in your code:
if(is_numeric($i) && $i >= 0) { return true; }
Check Sören's answer for more information concerning the difference between is_int() and is_numeric()
if(preg_match('/^[1-9]\d*$/',$i)) {
//Positive and > 0
}
Rather than checking for int OR string with multiple conditions like:
if ( ctype_digit($i) || ( is_int($i) && $i > 0 ) )
{
return TRUE;
}
you can simplify this by just casting the input to (string) so that the one ctype_digit call will check both string and int inputs:
if( ctype_digit( (string)$i ) )
{
return TRUE;
}
In addition to all the other answers: You are probably looking for ctype_digit. It looks for a string containing only digits.
Definition:
!A = !is_numeric($i)
B = $i < 1
!C = $i != round($i)
Then...
!is_numeric($i) || $i < 1 || $i != round($i) is equal to
!A || B || !C
So:
!A || B || !C = !A || !C || B
Now, using the deMorgan theorem, i.e. (!A || !C) = (A && C), then:
!A || !C || B = (A && C) || B
Now, note that A && C = is_numeric($i) && $i == round($i), but if $i == round($i) is TRUE, then is_numeric($i) is TRUE as well, so we can simplify A && C = C so,
(A && C) || B = C || B =
$i == round($i) || $i < 1
So you just need to use:
$i = $user_input_value;
if ($i == round($i) || $i < 1) {
return TRUE;
}
Laravel 4.2 Validation rule for positive number
It takes only positive numbers including float values.
public static $rules = array(
'field_name' => 'required|regex:/^\d*\.?\d*$/'
);
e.g:20,2.6,06
The first example is using round to verify that the input is an integer, and not a different numeric value (ie: a decimal).
is_int will return false if passed a string. See the PHP manual examples for is_int
To check for positive integer use:
$i = $user_input_value;
if (is_int($i) && $i > 0) {
return true; //or any other instructions
}
OR
$i = $user_input_value;
if (!is_int($i) || $i < 1) {
return false; //or any other instructions
}
Use the one that fits your purpose as they are the same. The following examples demonstrate the difference between is_numeric() and is_int():
is_numeric(0); // returns true
is_numeric(7); // returns true
is_numeric(-7); // returns true
is_numeric(7.2); // returns true
is_numeric("7"); // returns true
is_numeric("-7"); // returns true
is_numeric("7.2"); // returns true
is_numeric("abc"); // returns false
is_int(0); // returns true
is_int(7); // returns true
is_int(-7); // returns true
is_int(7.2); // returns false
is_int("7"); // returns false
is_int("-7"); // returns false
is_int("7.2"); // returns false
is_int("abc"); // returns false
All these answers overlook the fact that the requestor may checking form input.
The is_int() will fail because the form input is a string.
is_numeric() will be true also for float numbers.
That is why the $i == round($i) comes in as it checks for the input being a whole number.
Ok, I know this thread is really old but I share #Jeffrey Vdovjak's opinion: since I was able to find it, it might still help someone else out there.
php's gmp_sign() might be another easy way to check. It works for integer and numeric strings, and returns 1 if a is positive, -1 if a is negative, and 0 if a is zero.
So:
// positive
echo gmp_sign("500") . "\n";
// negative
echo gmp_sign("-500") . "\n";
// zero
echo gmp_sign("0") . "\n";
will output:
1
-1
0
See function manual at http://php.net/manual/en/function.gmp-sign.php
P.S. You'll need to have php_gmp.dll enabled in your .ini file.
This's my solution, hope helpful :
if (is_numeric($i) && (intval($i) == floatval($i)) && intval($i) > 0)
echo "positive integer";
i check if string is numeric, second check to sure it's integer and third to sure it positive
If you use "is_int" the variable must be integer, so it can't be a float value. (no round needed).
if(isset($i) && is_int($i) && $i >= 0){ //0 is technically a postive integer I suppose
return TRUE; //or FALSE I think in your case.
}
I would do something like this:
if ((int) $i > 0) {
// this number is positive
}
The number gets typecast to a positive or negative number depending on the minus sign being at the front. Then compares the typecast number to being greater than 0 to determine if the number is positive.
Related
What is the way to search the database (mysql/php code) for the following entries:
123XX
123XY
XYZ44
1X344
1Z344
Z23YY
The input letters are only X - Y - Z and the numbers from 0 to 9
They are all one number, which is (12344), so how can I show these results? The goal is to search for repeated entries.
Another example :
12XYY
X = 3,4,5,6,7,8,9,0
Y = 3,4,5,6,7,8,9,0
Provided that y is not equal to x or any apparent number (1,2)
And X is not equal to Y or any apparent number (1,2)
$number = "1XZYY";
$rnumber = str_replace(array('Y','X','Z'), "ـ", $number);
$lenNumber = strlen(5);
$duplicate = $mysqli->query("SELECT `number` FROM `listNumber` WHERE (length(`number`) = '$lenNumber' && `number` LIKE '%$rnumber%') OR (length(`number`) = '$lenNumber' && `number`LIKE '%$rnumber%')");
I tried many methods, but it was very slow in showing the results because I put the loop inside a loop to search for every number in the first loop
I understand you want to look for 12344, but some of the digits may be been redacted and replaced with a random capital letter in XYZ. For that, you can use a regular expression:
WHERE REGEXP_LIKE(foo, '^[XYZ1][XYZ2][XYZ3][XYZ4][XYZ4]$')
Demo
I would use PHP and occupy each digit into the correct position until I find a conflict. To prevent a double loop I use a dictionary helper object to hold values of X, Y and Z.
function match_str_to_number($str, $number)
{
if (strlen($number) != strlen($str)) {
return false;
}
$dict = ['X' => -1, 'Y' => -1, 'Z' => -1];
for ($i = 0; $i < strlen($number); $i++) {
if ($number[$i] != $str[$i]) {
// a number mismatch
if (!isset($dict[$str[$i]])) {
return false;
}
// a wildcard variable conflict
if ($dict[$str[$i]] != $number[$i] && $dict[$str[$i]] != -1) {
return false;
};
$dict[$str[$i]] = $number[$i];
}
}
return true;
}
echo match_str_to_number("XYZ44", "12344") ? "true" : "false";
echo match_str_to_number("XYZ4X", "12344") ? "true" : "false";
// output: truefalse
I have this function:
function return_a_number($source) {
switch ($source) {
case "0&0&0&0":
return 0;
case "0&0&1&1":
return 1;
case "1&1&1&1":
return 2;
}
}
Where $source have an ipotetic number concatenated with &.
How can i return 0 if $source have only '0' characters or 1 if have '0' and '1' characters or 2 if have only '1' characters?
// If there is a 0, ( check if there's also a one -> 1 or 0 ) : else only 1s => 2
return strpos($source, '0') !== false ? ( strpos($source, '1') !== false ? 1 : 0 ) : 2;
You could of course also write a regex, but why make it complicated if it works that simple. You might want to catch an empty string depending on your input.
Here is what the logic in your function should be, easy to understand and covers all three cases. Keep in mind that you must always check for 0 and 1 together first, then do it individually
if (strpos($source, '0') !== false && strpos($source, '1') !== false) {
return 0;
}
elseif (strpos($source, '0') !== false) {
return 1;
}
else {
return 2
}
You can put one more 'elseif' instead of the last 'else' if you might get different result than the 3 outcomes you mentioned
I'm looking for the fastest way to get this test.
So functions, operands and everything else is allowed.
I tried with the following regex (I'm not an expert):
0\.[0-9]+|100\.0+|100|[1-9]\d{0,1}\.{0,1}[0-9]+
It works except that it erroneously accept 0.0 or 0.000000 and so on.
Also it's not the most appropriated and fastest way.
(if anybody wants to fix the regex to don't allow those 0.00 values it would be appreciated)`
No need for regex:
if (is_numeric($val) && $val > 0 && $val <= 100)
{
echo '$val is number (int or float) between 0 and 100';
}
Demo
Update
It turns out you're getting the numeric values from a string. In that case, it would be best to extract all of them using a regex, something like:
if (preg_match_all('/\d+\.?\d*/', $string, $allNumbers))
{
$valid = [];
foreach ($allNumbers[0] as $num)
{
if ($num > 0 && $num <= 100)
$valid[] = $num;
}
}
You can leave out the is_numeric check, because the matched strings are guaranteed to be numeric anyway...
Use bccomp
This is a perfect use case for BCMath functions.
function compare_numberic_strings($number) {
if (
is_numeric($number) &&
bccomp($number, '0') === 1 &&
bccomp($number, '100') === -1
) {
return true;
}
return false;
}
echo compare_numberic_strings('0.00001');
//returns true
echo compare_numberic_strings('50');
//returns true
echo compare_numeric_strings('100.1');
//returns false
echo compare_numeric_strings('-0.1');
//returns false
From the manual:
Returns 0 if the two operands are equal, 1 if the left_operand is
larger than the right_operand, -1 otherwise.
I think your regex pattern should look like this:
^\d{1,2}$|(100)
Demo
I have a few strings stored in a database which contain specific rules which must be met. The rules are like this:
>25
>25 and < 82
even and > 100
even and > 10 or odd and < 21
Given a number and a string, what is the best way to evaluate it in PHP?
eg. Given the number 3 and the string "even and > 10 or odd and < 21" this would evaluate to TRUE
Thanks
Mitch
As mentioned in the comments, the solution to this can be very simple or very complex.
I've thrown together a function that will work with the examples you've given:
function ruleToExpression($rule) {
$pattern = '/^( +(and|or) +(even|odd|[<>]=? *[0-9]+))+$/';
if (!preg_match($pattern, ' and ' . $rule)) {
throw new Exception('Invalid expression');
}
$find = array('even', 'odd', 'and', 'or');
$replace = array('%2==0', '%2==1', ') && ($x', ')) || (($x');
return '(($x' . str_replace($find, $replace, $rule) . '))';
}
function evaluateExpr($expr, $val) {
$x = $val;
return eval("return ({$expr});");
}
This supports multiple clauses separated by and and or, with no parentheses and the and always being evaluated first. Each clause can be even, odd, or a comparison to a number, allowing >, <, >=, and <= comparisons.
It works by comparing the entire rule against a regular expression pattern to ensure its syntax is valid and supported. If it passes that test, then the string replacements that follow will successfully convert it to an executable expression hard-coded against the variable $x.
As an example:
ruleToExpression('>25');
// (($x>25))
ruleToExpression('>25 and < 82');
// (($x>25 ) && ($x < 82))
ruleToExpression('even and > 100');
// (($x%2==0 ) && ($x > 100))
ruleToExpression('even and > 10 or odd and < 21');
// (($x%2==0 ) && ($x > 10 )) || (($x %2==1 ) && ($x < 21))
evaluateExpr(ruleToExpression('even and >25'), 31);
// false
evaluateExpr(ruleToExpression('even and >25'), 32);
// true
evaluateExpr(ruleToExpression('even and > 10 or odd and < 21'), 3);
// true
Why don't you translate the string even to maths? If you use mods you can write it like that $number % 2 == 0. In that case, your example will be:
if(($number % 2 == 0 && $number > 10 ) || ($number % 2 != 0 && $number < 21)){
//Then it is true!
}
Hi all i have a post value which i am checking to see if its been posted it has atleast 4 numbers (digits) this works perfect.
if (isset($_POST['year']) &&
!preg_match('/([0-9]{4})/i', stripslashes(trim($_POST['year']))) ) {
now i want to check that the value is greater or = to a vairable and not sure how to achive what i need
i tried the below with no luck
$yearOff = date("Y")-150;
echo $yearOff;
if (isset($_POST['year']) &&
!preg_match('/([0-9]{4})/i', stripslashes(trim($_POST['year'])))
&& $_POST['year'] > $yearOff ) {
$ageerrors[] = '<span class="error">
You forgot enter your birth YEAR</span>';
}
Rather than an && you need an || OR condition to switch between the three possible invalid states (empty, not 4+ digits, or <= $yearOff:
if (!isset($_POST['year'])
// Lose the stripslashes()...
|| !preg_match('/([0-9]{4})/i',trim($_POST['year']))
|| $_POST['year'] > $yearOff
) {
// Invalid...
}
Note: It isn't clear from your description whether you want the value to be >= $yearOff or you want it to be < $yearOff. In other words, the code above is testing for the invalid state. Use whichever operator is appropriate for the invalid state.
Note 2: To test for at least 4 consecutive digits in the regex, a better pattern is something like:
/\d{4,}/
// If it must be *only* digits and no other characters, anchor with ^$
/^\d{4,}$/
There's no need for the overhead of a () capture group.
$yearOff = date("Y")-150;
echo $yearOff;
$input = #$_POST['year'];
if (!$input || strlen($input) !== 4 || $input < $yearoff) {
### MEEEP, ERROR ###
}
Explanation:
Input is set (not null which would be false), then it must have a string-length of four and finally it's numerical value must be higher or equal $yearOff.
I assigned the value of the input to it's own variable as well, because you only need to take it once out of $_POST.
As all these conditions are negated, I used the or || operator. Naturally the same can be expressed non-negated and with and:
if ($input && strlen($input) === 4 && $input >= $yearoff) {
### THIS IS CALL OKAY ###
}
To better debug this, the next step is to assign the validity to a variable as well:
$inputValid = $input && strlen($input) === 4 && $input >= $yearoff;
if (false === $inputValid) [
### MEEP, ERROR ####
}
Hope this is helpful.