Case insensitive function arguments - php

Is there a way to make php function arguments case insensitive? Right now I am looking for the word "Crossing" however "crossing" does not match. How can I make this argument case insensitive so I don't have to || each type of casing it could be put in as (if possible)
Function:
function endsWith($haystack, $needle) {
return $needle === "" || (($temp = strlen($haystack) - strlen($needle)) >= 0 && strpos($haystack, $needle, $temp) !== false);
}
PHP:
if(endsWith($searchResults, "Crossing")) {
$searchResults = str_replace("Crossing", "Xing", $searchResults);
}
This was resolved using the following:
if(stripos($searchResults, "Crossing")) {
$searchResults = str_ireplace("Crossing", "Xing", $searchResults);
}

You're looking for strnatcasecmp()
if( strnatcasecmp($varA, $varB) )
Ref: http://php.net/manual/en/function.strnatcasecmp.php
You can also just use strtolower() or strtoupper() for comparisons. Example:
if( 'test' == strtolower($variable) )
I personally just use the later in general as long as I know what is expected, but for comparison of two true variables where case is non-sensitive strnatcasecmp() is the way to go.

Related

Deprecated: strpos(): Non-string needles will be interpreted as strings in the future

I have this error appear in php 7.3
Deprecated: strpos(): Non-string needles will be interpreted as strings in the future. Use an explicit chr() call to preserve the current behavior
The line is :
if ($this->Category->getPath() && strpos('_', $this->Category->getPath())) {
It seems it come from this code : strpos('_', $this->Category->getPath()
$this->Category->getPath() can return this value for example :
int(8)
string(3) "8_9"
This worked for me
$suffix = strval($this->config->item('controller_suffix'));
$pos = !empty($suffix) ? strpos($class, $suffix) : FALSE;
if ($pos === FALSE)
{
$class .= $suffix;
}
parent::set_class($class);
All you have to do is pass in a string as the parameter for strpos.
strpos('_', strval($this->Category->getPath()))
Or, ensure the Category->getPath() returns a string and not a mixed type.
if (strpos($class, $suffix) === FALSE)
replace with
if ($suffix && strpos($class, $suffix) === FALSE)
Here you can see Details
https://github.com/raknjak/CIMembership/issues/22

Check if string starts with http or www or /

This works:
if (strpos($page, 'http') == 0) {
$link = 'Test';
}
But this doesn't:
if (strpos($page, 'http' || 'www' || '/') == 0) {
$link = 'Test';
}
I need to return something if $page does not begin with any of those three: http, www, or /.
if (strpos($page, 'http') == 0 || strpos($page, 'www') == 0 || strpos($page, '/') == 0) {
$link = 'Test';
}
you cannot use || like that.
Other than the 'bad arguments' answers above, you've also got a serious logic bug. strpos can and WILL return a boolean FALSE if the 'needle' string isn't found in the 'haystack'. e.g.
$needle = 'foo';
$haystack = 'bar';
if (strpos($haystack, $needle) == 0) {
echo 'found it!';
}
will say found it!, because strpos returned boolean FALSE, which PHP then typecast over to an int to compare to the 0. (int)FALSE becomes 0.
You need use the strict comparison operator === to make sure you really are comparing int to int, and not int to possibly-boolean-false:
if (strpos(...) === 0) { ... }
Unfortunately PHP doesn't understand "If the door is red or green or blue". You have to spoon-feed it "if the door is red or the door is green or the door is blue". But there's still some shortcuts you can take:
if( preg_match("(^(?:http|www|/))",$page)) $link = "Test";
I recommend using regular expressions for a case like this when you need to do pattern matching. More efficient in every way and way easier once you get the gist of it. This is a very helpful guide: http://oreilly.com/catalog/regex/chapter/ch04.html

How to return a boolean if a string contains one of an array of substrings?

I'm struggling with a simple function that loops through an array and returns true only if it finds a given substring in one of the array's elements.
For some reason, I'm ALWAYS getting false... even when the $email parameter is contains one of the valid domains. Ex: scoobydoo#domain1.com.
function check_email($email) {
$whitelist_domains = array(
'#domain1.com',
'#domain2.com',
'#domain3.com'
);
$output = FALSE;
foreach ($whitelist_domains as $domain) {
$pos = strpos( $email, $domain );
if ( $pos ) {
$output = TRUE;
}
}
return $output;
}
you are not breaking the loop if you find the domain, so what you are getting is actually the result for the LAST string checked only.
just add break; after $output = TRUE;
From the official doc of strpos:
Warning
This function may return Boolean FALSE, but may also return a
non-Boolean value which evaluates to FALSE. Please read the section on
Booleans for more information. Use the === operator for testing the
return value of this function.
And make sure to add a break after you set $output to true.
This is a good function to use the === operator with as it makes sure the value and type are equal (1==true, but 1!==true)
if (strpos( $email, $domain )!==false) {
$output = TRUE;
}
Change
if ( $pos ) {
to
if ( $pos !== false) {
this is because is strpos returns 0, that will equate to false, even though the string was found.
Here are two direct/common methods that have different advantages:
Method #1: non-regex approach
function check_email1($email){
$whitelist_domains=['#domain1.com','#domain2.com','#domain3.com'];
foreach($whitelist_domains as $domain){
if(strpos($email,$domain)!==false){
return true; // allow quick return (exit loop & function asap)
}
}
return false; // default response
}
Method #2: regex approach
function check_email2($email){
$whitelist_pattern='/#(?:domain1\.com|domain2\.com|domain3\.com)$/'; // condense if possible /#domain[123]\.com$/
return (bool)preg_match($whitelist_pattern,$email); // convert 0 or 1 output to boolean (false/true)
}
Demo Link
Input / Function Call:
$emails=['user#domain1.com','bad#bad.com'];
foreach($emails as $email){
echo "$email\n";
var_export(check_email1($email));
echo "\n";
var_export(check_email2($email));
echo "\n\n";
}
Output:
user#domain1.com
true
true
bad#bad.com
false
false
Advantages/Disadvantages:
strpos() in the majority of situations will outperform regex functions. Your default method should be to use string functions and only change to regex when string functions are less efficient or too convoluted to code. A related page: Which is more efficient, PHP string functions or regex in PHP?
Looping $whitelist_domains in #1 makes for a clunkier looking code block compared to #2 (which can be condensed to a one-liner if you write the pattern directly into preg_match()).
Simple/common mistakes sometimes occur when dealing with strpos(). These mistakes may include:
not checking for false in the if condition
writing the haystack and needle in the wrong order
#2 does require some knowledge about regex (escaping, character classes, alternatives, etc.) which can be a deterrent for inexperienced coders. Depending on how you write your regex pattern and how many domains will be whitelisted, #2 is likely to be harder to maintain than #1.
#2 has the added benefit of being able to check that the domain.com substring appears at the end of the word via the $ metacharacter. For this reason, regex offers stronger validation.
You should change your code in this:
function check_email($email) {
$whitelist_domains = array(
'#domain1.com',
'#domain2.com',
'#domain3.com'
);
foreach ($whitelist_domains as $domain) {
if ( strpos( $email, $domain ) !== false ) {
return true;
}
}
return false;
}
Documentation of strpos
Quoting from the manual (http://php.net/manual/en/function.strpos.php):
The !== operator can also be used. Using != would not work as expected
because the position of 'a' is 0. The statement (0 != false) evaluates
to false.
Example code
<?php
$mystring = 'abc';
$findme = 'a';
$pos = strpos($mystring, $findme);
// The !== operator can also be used. Using != would not work as expected
// because the position of 'a' is 0. The statement (0 != false) evaluates
// to false.
if ($pos !== false) {
echo "The string '$findme' was found in the string '$mystring'";
echo " and exists at position $pos";
} else {
echo "The string '$findme' was not found in the string '$mystring'";
}
?>

how to check the first three characters in a variable?

I have a viariable that contains something like this ab_123456789
how can i check if the variable starts with ab_?
thanks,
sebastian
Another way using substr:
if (substr('ab_123456789', 0, 3) === 'ab_')
Here substr is used to take the first 3 bytes starting at position 0 as a string that is then compared to 'ab_'. If you want to add case-insensivity, use strcasecmp.
Edit    To make the use more comfortable, you could use the following startsWith function:
function startsWith($str, $prefix, $case_sensitivity=false) {
if ($case_sensitivity) {
return substr($str, 0, strlen($prefix)) === $prefix;
} else {
return strcasecmp(substr($str, 0, strlen($prefix)), $prefix) === 0;
}
}
Note that these functions do not support multi-byte characters as only bytes are compared. An equivalent function with multi-byte support could look like this:
function mb_startsWith($str, $prefix, $case_sensitivity=false) {
if ($case_sensitivity) {
return mb_substr($str, 0, mb_strlen($prefix)) === $prefix;
} else {
return mb_strtolower(mb_substr($str, 0, mb_strlen($prefix))) === mb_strtolower($prefix);
}
}
Here the character encoding of both strings is assumed to be the internal character encoding.
Use regular expressions
$var = "ab_123456789";
if(preg_match('/^ab_/', $var, $matches)){
/*your code here*/
}
You can use strpos():
$text = "ab_123456789";
if(strpos($text, "ab_") === 0)
{
// Passed the test
}
The easiest way would be to get a sub string. e.g. substr('ab_123456789', 0, 3);
It's quite easy, as your string can be accessed like an array of characters. So you just have to do something like :
if ($var[0] == "a" && $var[1] == "b" && $var[2] == "c")
return true
You also could use a find function from php library.

Native function to filter array by prefix

Say I have an array with the following members:
car_porsche
car_mercedes
car_toyota
motorcycle_suzuki
motorcycle_honda
motorcycle_motoguzzi
How can I get an array with all the elements starting with car_? There was a native function for this but I forgot its name.
Do you know which function I mean? I know how to do it with for/foreach/array_filter. I'm quite sure there was a function for exactly this.
Well, you could do it using preg_grep():
$output = preg_grep('!^car_!', $array);
You could use array_filter() too but you have to pass a test function into that.
Regexp takes much more time to process, it`s better to use strpos() in this case:
foreach($arr AS $key => $val)
if(strpos(" ".$val, "car_") == 1)
$cars[$key] = $val;
This also works with keys:
You can write a simple routine which gives you the option of dropping the prefix in your returned array:
function filter_by_key_prefix ( $arr, $prefix, $drop_prefix=false ) {
$params = array();
foreach( $arr as $k=>$v ) {
if ( strpos( $k, $prefix ) === 0 ) {
if ( $drop_prefix ) {
$k = substr( $k, strlen( $prefix ) );
}
$params[ $k ] = $v;
}
}
return $params;
}
PHP 8 (2021):
I’m using str_starts_with for this purpose.
Performs a case-sensitive check indicating if haystack begins with needle.
→ Documentation
str_starts_with("car_porsche", "car_");
Assuming that the search needle is a user-supplied value, before using it in a regular expression, it should be passed through preg_quote() to ensure that any characters with special meaning are escaped.
Using a preg_ function offers the deepest tooling such as case-insensitivity, multibyte parsing, and word boundaries ...if desirable.
Reversing the filtration with preg_grep() is simply done with a function flag. To reverse the filtration with non-regex functions, just invert the return value or the comparison on the return value (depending on which technique you use.
Codes (Demo)
function keepIfStartsWith_regex($haystack, $needle) {
return preg_grep('/^' . preg_quote($needle, '/') . '/', $haystack);
}
function removeIfStartsWith_regex($haystack, $needle) {
return preg_grep('/^' . preg_quote($needle, '/') . '/', $haystack, PREG_GREP_INVERT);
}
For case-sensitive matching the leading characters of a string in PHP8, use iterated calls of the concise and intuitive str_starts_with() function.
function keepIfStartsWith_PHP8($haystack, $needle) {
return array_filter($haystack, fn($v) => str_starts_with($v, $needle));
}
function removeIfStartsWith_PHP8($haystack, $needle) {
return array_filter($haystack, fn($v) => !str_starts_with($v, $needle));
}
For PHP versions under 8, you can make iterated calls of strpos() for case-sensitive or stripos() for case-insensitive matching. You must explicitly check if the return value is identical to 0 because performing a loose comparison (type-juggled comparison) will mistake 0 for false when no match is found.
function keepIfStartsWith_PHP7_4($haystack, $needle) {
return array_filter($haystack, fn($v) => strpos($v, $needle) === 0);
}
function removeIfStartsWith_PHP7_4($haystack, $needle) {
return array_filter($haystack, fn($v) => strpos($v, $needle) !== 0);
}
function keepIfStartsWith_sub7_4($haystack, $needle) {
return array_filter($haystack, function($v) use($needle) { return strpos($v, $needle) === 0; });
}
function removeIfStartsWith_sub7_4($haystack, $needle) {
return array_filter($haystack, function($v) use($needle) { return strpos($v, $needle) !== 0; });
}
I think you can use array_filter() for that purpose.

Categories