Function condition based on array length - php

The title might sound... trivial, but i had no idea how to name this problem in one sentence.
I have different arrays of variables in different places in my file(s)
for example:
//set1:
$a =1;$b=2;$c=3;$d=4;$e=5;
$set1 =array($a,$b,$c,$d,$e);
//set2:
$x=1;$y=2;
$set2 =array($x,$y);
Im tryin' to write a function which makes different operations based on array length.
For (simplified) example, in first case I wanna execute:
if($set1[0]){/*something*/}
if($set1[0] || $set1[1]){}
if($set1[0] || $set1[1] || $set1[2]){}
if($set1[0] || $set1[1] || $set1[2] || $set1[3]){}
if($set1[0] || $set1[1] || $set1[2] || $set1[3] || $set1[4]){}
In second case, I wanna execute
if($set2[0]){}
if($set2[0] || $set2[1]){}
I tried to write function using eval(), and it works...
function _f($array)
{
$i =-1;
$x =count($array);
$str ='';
$str2 ='';
while(++$i < $x)
{
if($i ==0){
$str .="\$array[$i]";
} else {
$str .=" || \$array[$i]";
}
$str2 .="if(".$str."){\n echo 'lol'; \n}\n\n";
}
echo "<pre>";
echo $str2;
echo "</pre>";
eval($str2);
}
_f($set1);
//output: lollollollollol (as I expected)
...but is that solution safe when user can set the variables? Are there better solutions?

It is not entirely clear what the intention of your program is because of the limitations of the input data, as mentioned in comment above (all $array entries evaluate to true).
But the following sequence, which would replace your loop, would produce the same result as the evals:
$status = false;
while(++$i < $x) {
$status = $status || $array[$i];
if ($status) echo 'lol';
}

Related

regex not working as expected when matching file names with wildcards

I am writing a PHP function that takes an array of file names and removes file names from the array if they do not match a set of criteria input by the user. The function iterates through the array and compares each value to a regex. The regex is formed by inserting variables from user input. If the user didn't specify a variable, regex wildcard characters are inserted in the variable's place. The file names are all very systematic, like 2020-06-N-1.txt so I know exactly how many characters to expect in the file names and from the user input. However, when I run the code, file names that don't match the regex are still in the array. Some non-matching file names are taken out, but many others are left in. Parts of my PHP code are below. Any help is appreciated.
function fileFilter() {
global $fileArray, $fileFilterPattern;
/* The loop starts at 2 and goes to count()-1 because the first 2 elements were removed
earlier with unset */
for ($j = 2; $j < count($fileArray) - 1; $j++) {
if(!(preg_match($fileFilterPattern, $fileArray[$j]))) {
unset($fileArray[$j]);
}
}
return;
}
// If user does not provide a filter value, it gets converted into wildcard symbol
if ($month == '') {
$month = '..';
}
if ($year == '') {
$year = '....';
}
if ($section == '') {
$section = '.';
}
$fileFilterPattern = "/{$year}-{$month}-{$section}-.\.txt/";
/* function only runs if user applied at least one filter */
if (!($month == '..' && $year == '....' && $section == '.')) {
fileFilter();
}
Below I have included an example of how the array contains elements that aren't matches. I obtain my output array using echo json_encode($fileArray);
My input:
month is ""
year is ""
section is "L"
Expected result:
Array contains only files that have L in the section spot (YEAR-MONTH-**SECTION**-NUMBER.txt)
Resulting array:
{"8":"2020-06-L-1.txt","9":"2020-06-L-2.txt","10":"2020-06-L-3.txt","11":"2020-06-L-4.txt","12":"2020-06-L-5.txt","15":"2020-06-N-3.txt","16":"2020-06-N-4.txt","17":"2020-06-N-5.txt","18":"2020-06-N-6.txt","19":"2020-06-O-1.txt","20":"2020-06-O-2.txt","21":"2020-06-O-3.txt","22":"2020-06-O-4.txt","23":"2020-06-S-1.txt","24":"2020-06-S-2.txt","25":"2020-06-S-3.txt"}
The problem is using unset() inside a loop. On the next iteration, the index is no longer the same as it was before you messed with the array using unset(). Sometimes, you deal with this by using array_values(), but in this case it's simpler to just build a second array that has only the values you want. The following code works. I've used array_values() just to take the string that you provided and get the indexes back to normal.
That said, since the "first 2 elements were removed
earlier with unset" you need to run array_values() on the array before you get to this part.
<?php
$str ='{"8":"2020-06-L-1.txt","9":"2020-06-L-2.txt","10":"2020-06-L-3.txt","11":"2020-06-L-4.txt","12":"2020-06-L-5.txt","15":"2020-06-N-3.txt","16":"2020-06-N-4.txt","17":"2020-06-N-5.txt","18":"2020-06-N-6.txt","19":"2020-06-O-1.txt","20":"2020-06-O-2.txt","21":"2020-06-O-3.txt","22":"2020-06-O-4.txt","23":"2020-06-S-1.txt","24":"2020-06-S-2.txt","25":"2020-06-S-3.txt"}';
$fileArray = json_decode($str, true);
$fileArray = array_values($fileArray);
echo '<p>fileArray: ';
var_dump($fileArray);
echo '</p>';
function fileFilter() {
global $fileArray, $fileFilterPattern;
$filteredArray = [];
for ($j = 0; $j < count($fileArray); $j++) {
if(preg_match($fileFilterPattern, $fileArray[$j]) === 1) {
//unset($fileArray[$j]);
array_push($filteredArray, $fileArray[$j]);
}
}
echo '<p>filteredArray: ';
var_dump($filteredArray);
echo '</p>';
//return;
}
$month =='';
$year = '';
// If user does not provide a filter value, it gets converted into wildcard symbol
if ($month == '') {
$month = '..';
}
if ($year == '') {
$year = '....';
}
if ($section == '') {
$section = '.';
}
$section = 'L';
$fileFilterPattern = "#{$year}-{$month}-{$section}-.\.txt#";
echo '<p>fileFilterPattern: ';
var_dump($fileFilterPattern);
echo '</p>';
/* function only runs if user applied at least one filter */
if (!($month == '..' && $year == '....' && $section == '.')) {
fileFilter();
}
?>
The main problem is that the count decreases each time you unset, so you should define the count once. Assuming the -1 and $j = 2 are correct for your scenario:
$count = count($fileArray) - 1;
for ($j = 2; $j < $count; $j++) {
if(!(preg_match($fileFilterPattern, $fileArray[$j]))) {
unset($fileArray[$j]);
}
}
There are others ways where you don't have to assume and then keep track of the keys:
foreach($fileArray as $k => $v) {
if(!preg_match($fileFilterPattern, $v)) {
unset($fileArray[$k]);
}
}
I would get rid of your fileFilter function and use this handy function instead, which will return all items that match the pattern:
$fileArray = preg_grep($fileFilterPattern, $fileArray);

How do I use PHP to compare one variable to any odd number instance of another variable?

I want to compare the session[name] to all the even instances of text.
For example:
$_SESSION['name'] === $text[1] or $text[2] or $text[4] or $text[6]
The problem with doing it like the way above is that the code above will limit to only 6. Is there any way to just say "compare this to all the even instances of '$text' "?
Basically what I'm trying to do is say:
Compare $_SESSION['name'] to all even info from the $Text array.
So for example if this was my array:
$text = array("info0", "info1", "info2", "info3")
I would want to compare something to all the even info instances in the array(ie: info0, info2)
The code:
//compare the strings
if ($_SESSION['name'] === $text[0] && $_SESSION['pass'] == $text[1]) {
//echo "That is the correct log-in information";
header("Location: home.php");
} else {
echo "That is not the correct log-in information.";
}
XaxD's answer is good, and probably what you are interested in, but if you are using an associative array and want to look at every other element of the array this will work:
function checkEvenValues($text)
{
$skip = array(true, false);
// set $iskp to 0 if you want the first element to be counted as even; else, set it to 1
$iskp = 0;
foreach ($text as $idx=>$val)
{
$skp = 1 - $skp;
if ($skip[$iskp]) continue;
if($_SESSION['name'] == $text[$i]) return (true);
}
return (false);
}
function checkEvenValues($text)
{
if($_SESSION['name'] === $text[1]) return true;
for($i = 2; $i < count($text); $i += 2)
{
if($_SESSION['name'] === $text[$i])
return true;
}
}
Presuming that your keys are the same as the numbers in your values ([0] => 'info0') etc, you can use something like this combining some PHP array functions to filter down to only even keys (including 1), then a strict in_array() check to determine if it's there:
function compareEvens($text, $compare) {
// swap keys for values (back again)
$evens = array_flip(
// apply custom filter function
array_filter(
// swap keys for values
array_flip($text),
// return if its even OR its one
function($key) {
return $key % 2 === 0 || $key === 1;
}
)
);
return in_array($compare, $evens, true);
}
Example:
$text = array("info0", "info1", "info2", "info3");
var_dump(compareEvens($text, 'info2')); // true
var_dump(compareEvens($text, 'info3')); // false
Docs:
array_flip()
array_filter()
in_array()

PHP string sort by letter range can't execute single character comparison

I'm working on outputing a list of companies in a foreach statement. To compare the first letters of each company I'm substinging the first character of each. These need to be sent through an if comparitor operation to see if it's the first occurance of each range of inital character. The var_dump shows that the srt_cmp has found the values intended. When I use the value in a if comparison for many combination, the if statement will not execute.
<?php
$stringCompanyListing = '<!-- beginning of business listing -->'."\n";
$countCompanies=0;
$haveStrungAD = "";
$haveStrungEI = "";
$haveStrungJO = "";
$haveStrungPU = "";
$haveStrungVZ = "";
foreach ($files as $file){
$company = new SimpleXMLElement($file, 0, true);
$COMPANYKEY[$countCompanies] = basename($file, '.xml');
if ($countCompanies >= 1){
$currentCompany = substr($COMPANYKEY[$countCompanies],0, 1);
$previousCompany = substr(($COMPANYKEY[($countCompanies-1)]),0, 1);
$checkForNavigation = strcmp($previousCompany, $currentCompany);
// var_dump at this point show intended values such as "A" and "-1"
if ($haveStrungAD == ""){
if ($currentCompany == range("A", "D")){
if ($checkForNavigation <= -1){
$stringCompanyListing .= ' <div class="categoryHeading"><a name="atod"></a>A-D</div>';
$haveStrungAD = "done";
}
}
}
if ($haveStrungEI == ""){
if ($currentCompany == range("E", "I")){
if ($checkForNavigation <= -1){
$stringCompanyListing .= ' <div class="categoryHeading"><a name="etoi"></a>E-I</div>';
$haveStrungEI = "done";
}
}
}
// more if comparisons omitted
}
$countCompanies++;
}
Since you have all the company names in an array ($COMPANYKEY), couldn't you just sort the array using either usort () or uasort() (depending on if you need the keys to remain attached to the values). Then loop through the array and assign companies to the appropriate array. For example,
uasort($COMPANYKEY, function ($a, $b) {
return $a < $b;
});
foreach ($COMPANYKEY AS $comp)
{
$char = substr($comp, 0, 1); //get first letter
if ($char <= 'd')
$atod[] = $comp;
elseif ($char > 'd' && $char <= 'm')
$etom[] = $comp;
}
You can write additional conditions to load into the company into additional arrays, or you can use a switch statement on $char and write a bunch of cases. Either way, this should load each.
Additionally, if you are using your code, you need to not use == operator and use the inarray() function. range returns an array of values, so you need to check if your value is that array, not is equal to an array.
Hope this helps.

How Can I get the string that present the variable in function argument?

How Can I get the string that present the variable in function argument?
example
function dbg($param){
return "param";
}
$var="Hello World";
echo dgb($var);
output: var
$arr=array();
echo dgb($arr);
output: arr
It is NOT possible to do what you ask reliably.
The closest you can come up to doing that is to do a debug_backtrace() to check which file called the function then tokenize the source of that file to find the reference.
Again, this will not work reliably. It will fail if you have multiple calls on one line. Truthfully, it isn't work the trouble. You are writing the code anyway, you know which variable you are passing.
function dbg($var) {
$bt = debug_backtrace();
$file = $bt[0]['file'];
$line = $bt[0]['line'];
$source = file_get_contents($file);
$tmpTokens = token_get_all($source);
$tokens = array ();
foreach ($tmpTokens as $token) {
if (is_array($token) && $token[0] !== T_INLINE_HTML && $token[0] !== T_WHITESPACE) {
$tokens[] = $token;
}
}
unset($tmpTokens);
$countTokens = count($tokens);
for ($i = 0; $i < $countTokens; $i++) {
if ($tokens[$i][3] > $line || $i === $countTokens - 1) {
$x = $i - (($tokens[$i][3] > $line) ? 1 : 0);
for ($x; $x >= 0; $x--) {
if ($tokens[$x][0] === T_STRING && $tokens[$x][1] === __FUNCTION__) {
if ($x !== $countTokens - 1 && $tokens[$x + 1][0] === T_VARIABLE) {
return $tokens[$x + 1][1];
}
}
}
}
}
return null;
}
printing a variable, you're doing it wrong.
the right ways is like this:
function dbg($param){
return $param;
}
$var="Hello World";
echo dgb($var);
and by the way you're passing an array to a function that only accepts variables. and oh it's a null array all the way worse!
I'm just guessing that you're trying to make a custom debugger which as a nice touch prints the name of the variable you're debugging. Well, that's not really possible. I'd suggest you look at debug_backtrace, which allows you to print the file, line number, function name and arguments of the place where you invoked your dbg function. Unless you use dbg more than once per line that helps you find the information you're looking for, and IMO is a lot more useful anyway.
Alternatively, you can have both the name and value of your variable if you call your function like this:
function dbg($var) {
echo 'name: ' . key($var) . ', value: ' . current($var);
}
$foo = 'bar';
dbg(compact('foo'));
You question doesnt make much sense, you may want to reword it.
It sounds like you want to use the $param in the function in which case you can just do something link echo $param;

PHP If Statement with Multiple Conditions

I have a variable$var.
I want echo "true" if $var is equal to any of the following values abc, def, hij, klm, or nop. Is there a way to do this with a single statement like &&??
An elegant way is building an array on the fly and using in_array():
if (in_array($var, array("abc", "def", "ghi")))
The switch statement is also an alternative:
switch ($var) {
case "abc":
case "def":
case "hij":
echo "yes";
break;
default:
echo "no";
}
if($var == "abc" || $var == "def" || ...)
{
echo "true";
}
Using "Or" instead of "And" would help here, i think
you can use in_array function of php
$array=array('abc', 'def', 'hij', 'klm', 'nop');
if (in_array($val,$array))
{
echo 'Value found';
}
Dont know, why you want to use &&. Theres an easier solution
echo in_array($var, array('abc', 'def', 'hij', 'klm', 'nop'))
? 'yes'
: 'no';
you can use the boolean operator or: ||
if($var == 'abc' || $var == 'def' || $var == 'hij' || $var == 'klm' || $var == 'nop'){
echo "true";
}
You can try this:
<?php
echo (($var=='abc' || $var=='def' || $var=='hij' || $var=='klm' || $var=='nop') ? "true" : "false");
?>
I found this method worked for me:
$thisproduct = "my_product_id";
$array=array("$product1", "$product2", "$product3", "$product4");
if (in_array($thisproduct,$array)) {
echo "Product found";
}
Sorry to resurrect this, but I stumbled across it & believe it adds value to the question.
In PHP 8.0.0^ you can now use the match expression like so:
<?php
echo match ($var) {
'abc','def','hij','klm' => 'true',
};
?>
//echos 'true' as a string
Working link from OnlinePHPfunctions
PHP Manual
Try this piece of code:
$first = $string[0];
if($first == 'A' || $first == 'E' || $first == 'I' || $first == 'O' || $first == 'U') {
$v='starts with vowel';
}
else {
$v='does not start with vowel';
}
It will be good to use array and compare each value 1 by 1 in loop. Its give advantage to change the length of your tests array. Write a function taking 2 parameters, 1 is test array and other one is the value to be tested.
$test_array = ('test1','test2', 'test3','test4');
for($i = 0; $i < count($test_array); $i++){
if($test_value == $test_array[$i]){
$ret_val = true;
break;
}
else{
$ret_val = false;
}
}
I don't know if $var is a string and you want to find only those expressions but here it goes either way.
Try to use preg_match http://php.net/manual/en/function.preg-match.php
if(preg_match('abc', $val) || preg_match('def', $val) || ...)
echo "true"

Categories