Why strpos + strlen is not secure in PHP (ex: exact matching) - php

I had a discussion with my teacher about the mb_ functions. Whatever, one thing leading to another, we changed the subject and he gave me an example where strpos and strlen could be problematic, according to him:
$input = "something"; # input given by the user
$string = "hello"; # string to match
if ( strpos($input, $string) !== false && strlen($input) < strlen($string) ) {
echo "Correct input";
} else {
echo "Incorrect input";
}
(The question is not about how to match 2 strings)
According to my teacher, there may be a way to validate the statement and execute the code echo "Correct input";.
However, I can't see a flaw in this. Maybe there could be a problem with encoding? Do you have any idea?

okey i think that the flaw will be the if statement logic
how will you use strpos function which check the position of the first occurrence of a substring in a string , and in the same time you want to check if the input is greater than the subject ?
by logic it is impossible

Related

startsWith Case sensitive

Can't find a solution to this which seems simple enough. I have user input field and want to check the user has prefixed the code asked for with an S (example code S123456 so I want to check to make sure they didn't just put 123456).
// Function to check string starting with s
if (isset($_REQUEST['submitted'])) { $string=$_POST['required_code'];function startsWith ($string, $startString){$len = strlen($startString);return (substr($string, 0, $len) === $startString);
}
// Do the check
if(startsWith($string, "s"))echo "Code starts with a s";else echo "Code does not start with a s";}
The problem is if the user inputs an upper case S this is seen as not being a lower case s.
So I can get round this using
$string = strtolower($string);
So if the user inputs an uppercase S it gets converted to lower case before the check. But is this the best way? Is there not someway to say S OR s?
Any suggestions?
What you could do instead of creating your own function, is using stripos. Stripos tries to find the first occurrence of a case-insensitive substring.
So as check you could have:
if(stripos($string, "s") === 0)
You need 3 equal signs, since stripos will return false (0) if it can't find the substring.
Take your pick; there are many ways to see if a string starts with 'S'. Some of them case-sensitive, some not. The options below should all work, although I wouldn't consider any of them better than your current solution. stripos() is probably the 'cleanest' check though. If you need multibyte support, there's also the mb_stripos() variant.
(Although; keep in mind that stripos() can also return false. If you're going with that option, always use the stricter "identical" operator ===, instead of == to prevent type juggling.)
if (stripos($string, 's') === 0) {
// String starts with S or s
} else {
// It does not
}
if (str_starts_with($string, 's') || str_starts_with($string, 'S')) // ...
if (in_array(substr($string, 0, 1), ['S', 's'], true)) // ...
if (preg_match('/^s/i', $string)) // ...
// Many other regexp patterns also work
Thanks all, it was
if (str_starts_with($string, 's') || str_starts_with($string, 'S')) // ...
I was looking for I had tried
if (str_starts_with($string, 's' || 'S')) // ...

PHP - Check for leading 0's in 2 comma-delimited integers

I have a user-input string with 2 comma-delimited integers.
Example (OK):
3,5
I want to reject any user input that contains leading 0's for either number.
Examples (Bad):
03,5
00005,3
05,003
Now what I could do is separate the two numbers into 2 separate string's and use ltrim on each one, then see if they have changed from before ltrim was executed:
$string = "03,5";
$string_arr = explode(",",$string);
$string_orig1 = $string_arr[0];
$string_orig2 = $string_arr[1];
$string_mod1 = ltrim($string_orig1, '0');
$string_mod2 = ltrim($string_orig2, '0');
if (($string_mod1 !== $string_orig1) || ($string_mod2 !== $string_orig2)){
// One of them had leading zeros!
}
..but this seems unnecessarily verbose. Is there a cleaner way to do this? Perhaps with preg_match?
You could shorten the code and check if the first character of each part is a zero:
$string = "03,5";
$string_arr = explode(",",$string);
if ($string_arr[0][0] === "0" || $string_arr[1][0] === "0") {
echo "not valid";
} else {
echo "valid";
}
Here is one approach using preg_match. We can try matching for the pattern:
\b0\d+
The \b would match either the start of the string, or a preceding comma separator.
If we find such a match, it means that we found one or more numbers in the CSV list (or a single number, if only one number present) which had a leading zero.
$input = "00005,3";
if (preg_match("/\b0\d+/", $input)) {
echo "no match";
}
You can do a simple check that if the first character is 0 (using [0]) or that ,0 exists in the string
if ( $string[0] == "0" || strpos($string, ",0") !== false ) {
// One of them had leading zeros!
}
All the current answers fail if any of the values are simply 0.
You can just convert to integer and back and compare the result.
$arr = explode(',', $input);
foreach($arr as $item) {
if( (str)intval($item) !== $item ) {
oh_noes();
}
}
However I am more curious as to why this check matters at all.
One way would be with /^([1-9]+),(\d+)/; a regex that checks the string starts with one or more non-zero digits, followed by a comma, then one or more digits.
preg_match('/^([1-9]+),(\d+)/', $input_line, $output_array);
This separates the digits into two groups and explicitly avoids leading zeros.
This can be seen on Regex101 here and PHPLiveRegex here.

How to disable ' - ; : ~ ` from input and remove from string?

I tried to add extra security by removing special characters. I want to allow letters, numbers and ? = & only.
I tried:
if (strpos($_SERVER['REQUEST_URI'],'\'')) { echo 'true'; }
I cannot just simply put ' in between the '' as it breaks it so I tried adding the \ but it didn't work.
Is there a way to detect all the symbols in the url string or input field?
EDIT:
tried adding < simply into the list
if (preg_match('#[#*,!$\'\-;:<>~`^|\(\\)\\{\\}\\[\\]]#i', $_SERVER['REQUEST_URI']) || strpos($_SERVER['REQUEST_URI'],'script')) {
echo 'Cannot do that';
}
I tried adding ([\<])([^\>]{1,})*([\>]) into there but it didn't work.
I also tried adding a condition if strcmp($_SERVER['REQUEST_URI'], strip_tags($_SERVER['REQUEST_URI'])) != 0
and when i added into the url, it didn't do anything
Use preg_match to test for anything but the characters you want:
if (preg_match('#[^a-z0-9?=&]#i', $str)) { echo 'true'; }
Use preg_replace to remove them:
$str = preg_replace('#[^a-z0-9?=&]#i', '', $str);
If you just want to prohibit certain characters, use a regular expression that just matches those characters:
if (preg_match('#[\'\-;:~`]#i', $str)) { echo 'true'; }
You can fix that using double quotes as strings delimiter, try this
if (strpos($_SERVER['REQUEST_URI'],"'")) { echo 'true'; }
One thing that none of the posts addressed is why strpos didn't work for you. strpos can return two types. It can return an integer that is greater than or equal to zero. 0 being the first character. It can also return a boolean type false. To check if if strpos found a match it would have to have been written like this:
if (strpos($_SERVER['REQUEST_URI'],'\'') !== false) { echo 'true'; }
From the PHP Documentation The comparison $a !== $b operator works this way:
return TRUE if $a is not equal to $b, or they are not of the same type.
Information on strpos returning two types (boolean false or an integer) can be found in this PHP strpos Documentation. In particular:
Returns the position of where the needle exists relative to the beginning of the haystack string (independent of offset). Also note that string positions start at 0, and not 1.
Returns FALSE if the needle was not found.
So as you can see 0 and false are not the same thing which is why your test failed.
As for security and strings in PHP I recommend you look at this StackOverflow article for some opinions on the matter.

PHP Regex - Value of 1 or more integers [duplicate]

This question already has answers here:
php validate integer
(7 answers)
Closed 9 years ago.
Hey I'm trying to perform input validation in PHP to ensure that the stock values that are typed in are at least 1 positive integer and from 0-9. Should not contain any special characters.
For example, any of the following values should be valid:
7
0
32
47534
The following SHOULD NOT be valid:
asdf
35/gdf
../34.
etc..
I'm using the following if statement to check for the positive integer value of "$original_stock".
if (preg_match("/^[0-9]$/", $original_stock))
{
$error .="Original stock must be numerical.";
}
Additionally, I have a price field which should be validated as either an int or a double.
If there's an easier alternative to using regex, that's okay too!
Thanks in advance :)
Try this regexp:
/^\d+$/
The issue with your existing regexp is that it only matches strings with exactly one digit.
As for validating an int or a double:
/^\d+\.?\d*$/
Note that that regexp requires that there be at least one digit.
Use:
/^[0-9]+$/
The + means "one or more". Without it, your regex will only match a single digit. Or you could use the simpler variant:
/^\d+$/
For floats, try something like:
/^\d+(\.\d{1,2})?/
This will match one or more digits, optionally followed by a . and one or two digits. (i.e. .12 will not match.)
To save yourself some headaches, you can also use the is_int and is_float functions.
Lastly; note that your check is wrong. preg_match will return 0 if it fails, so you should write it as:
if (!preg_match("/^\+$/", $original_stock)) {
// error
}
(note the !).
You may want to use the
is_int
Don't reinvent a wheel slower than an existing one, use a motorcycle: is_int.
#Assuming $original_stock is a single value...
if (is_int($original_stock)) {
#Valid, do stuff
}
else {
#Invalid, do stuff
}
#Assuming $original_stock is an array...
$valid = true;
foreach ($original_stock as $s) {
if (!is_int($s)) {
$valid = false;
break;
}
}
if ($valid) {...}
else {...}
I just ran into this exact problem and solved it this way using the regex.
I think the problem is your caret ^.
/^[0-9]$/
I moved it inside the class and got the results I needed.
function validate_int($subject)
{
//Pattern is numbers
//if it matches anything but numbers, we want a fail
$pattern = '/[^0-9]/';
$matches = preg_match($pattern, $subject);
if($matches > 0)
return false;
else
return true;
}

Check if string contains another string

In php is there a way i can check if a string includes a value.
Say i had a string "this & that", could i check if that included "this".
Thanks
UPDATED:
$u = username session
function myLeagues2($u)
{
$q = "SELECT * FROM ".TBL_FIXTURES." WHERE `home_user` = '$u' GROUP BY `compname` ";
return mysql_query($q, $this->connection);
}
That code returns if there is an exact match in the database.
But i put two usernames together like "username1 & username2" and need to check if the username session is present in that field.
Is that a way to do this? It obviously woudn't equal it.
ANOTHER UPDATE:
If i use the like %username% in the sql, will it appear if its just the username. So rather than Luke & Matt being shown, if its just Luke will that show too? I dont want it to, i just want things that arent. Can you put != and LIKE so you only get similar matches but not identical?
Cheers
Use strstr or strpos functions. Although there are regex ways too but not worth for such trivial task there.
Using strstr
if (strstr('This & That', 'This') !== false)
{
// found
}
Using strpos
if (strpos('This & That', 'This') !== false)
{
// found
}
I like stristr the best because it is case insensitive.
Usage example from php.net:
$email = 'USER#EXAMPLE.com';
echo stristr($email, 'e'); // outputs ER#EXAMPLE.com
echo stristr($email, 'e', true); // As of PHP 5.3.0, outputs US
based on your update
I think you want to use the like statement
SELECT * FROM table
WHERE home_user LIKE "%username1%" OR home_user LIKE "%username2%"
GROUP BY compname
The % Is your wild card.
<?php>
$string = 'this & that';
if (strpos($string, 'this') === FALSE) {
echo 'this does not exist!';
} else {
echo 'this exists!';
}
?>
What's noteworthy in the check is using a triple equal (forget the actual name). strpos is going to return 0 since it's in the 0th position. If it was only '== FALSE' it would see the 0 and interpret it as FALSE and would show 'this does not exist'. Aside from that this is about the most efficient way to check if something exists.
preg_match('/this/','this & that');
This returns the number of matches, so if it's 0, there were no matches. It will however stop after 1 match.
Regular expressions can be checked with preg-match.

Categories