I'm trying to check MD5 of some data with md5 some files, both of them are stored in one dimensional arrays. Say I have 4 files in the $files array with the same number of $datas, the following code prints "NO DIFFERENCE" 12 times instead of 4 times.
foreach($files as $file) {
foreach($datas as $data) {
if(md5($data) !== md5_file($file)) {
echo "NO DIFFERENCE";
}
}
}
How do I prevent duplicating a loop?
Update:
Both arrays $datas and $files contains equal number of values but the tricky part is the values in $files array starts from key number 2 (because I removed "." and ".." from scandir result) whereas in $datas array values start from key number 0.
the following code prints "NO DIFFERENCE" 12 times instead of 4 times.
The reason for that is you have a nested loop.
For each value in the $files array, your inner foreach will run once.
So say if you have 3 values in $files and 4 values in $datas, the loop will run as follows:
First value in $files iterated
Inner loop runs, and iterates through all 4 values in $datas
Second value in $files iterated
Inner loop runs, and iterates through all 4 values in $datas
Third value in $files iterated
Inner loop runs, and iterates through all 4 values in $datas
Try this with one loop like this :
foreach($datas as $key => $value) {
if(md5($value) !== md5_file($files[$key])) {
echo "NO DIFFERENCE";
}
}
Note: The loop work when you have same no of values for both arrays
If you want to compare md5(files) to the mfs5(datas) you can simply do this:
for ($i = 0; $i < sizeof($files); $i++){
if(md5($datas[$i]) !== md5_file($files[$i+2]))
echo "NO DIFFERENCE";
}
If you want to check if each file have one corresponding md5(datas) then you should use you double loop as you did.
First, are you sure that !== is the operator you want to use to say 'no difference' ?
If you are looking for equality, maybe you want to use ===
Second, md5(...) is time consuming, so extract the hash in a variable.
Third, if you mean equality, you can add a break in the inner loop to stop looping as soon as you find the equality.
foreach($files as $file) {
$md5File = md5_file($file); // extract in a variable
foreach($datas as $data) {
if(md5($data) === $md5File) { // === instead of !==
echo "NO DIFFERENCE";
break; // break as soon as possible
}
}
}
You could use a callback function. But then you should be clear about how exactly you will describe an algorithm of your problem.
The following sample shows how to maybe achieve it. But it assumes that the arrays are in the same order and that you don't want to cross-compare everything. Also array_udiff may not be the best approach for it.
function compare_by_md5($data, $file) {
if( md5($data) === md5_file($file)) {
echo "NO DIFFERENCE";
}
}
array_udiff($datas, $files, 'compare_by_md5');
Sample is shown here: http://codepad.org/lYOyCuXA
If you simply want to detect if there is a difference:
$dataHashes = array();
foreach($datas as $data) {
$dataHashes[md5($data)] = true;
}
$different = false;
foreach($files as $file) {
if(!isset($dataHashes[md5_file($file)])) {
$different = true;
break;
}
}
var_dump($different);
If you want to know which files are different, then:
$dataHashes = array();
foreach($datas as $data) {
$dataHashes[md5($data)] = true;
}
foreach($files as $file) {
if(!isset($dataHashes[md5_file($file)])) {
echo $file, 'is different', PHP_EOL;
}
}
Related
I have been looking and testing for a week with no luck.
I want to seach the csv file for a location with the following php file:
<?php
$csv = fopen("file.csv", "r");
$row = fgetcsv($csv);
foreach($_POST as $key => $value)
{
$result = $key;
}
while ($row = fgetcsv($csv)) {
if(in_array($result, $row)) {
echo json_encode($row);
}
}
?>
This works for one portion that I need it to. I have a second section which needs to do the same, except return ONLY the first result from the csv, but is instead returning multiple rows for all locations that it matches and I have tried removing the while loop
As #Fellipe commented above, you can break out of the loop in a few ways, easiest is simple break; statement
For example:
<?php
$csv = fopen("file.csv", "r");
$row = fgetcsv($csv);
foreach($_POST as $key => $value)
{
$result = $key;
}
while ($row = fgetcsv($csv)) {
if(in_array($result, $row)) {
echo json_encode($row);
break; // exit while() loop
}
}
?>
Also read the doco if your nesting loops (loops within loops). You then just pass in an int matching how many levels to 'break', ie: break 2;
http://php.net/manual/en/control-structures.break.php
break (PHP 4, PHP 5, PHP 7)
break ends execution of the current for, foreach, while, do-while or
switch structure.
break accepts an optional numeric argument which tells it how many
nested enclosing structures are to be broken out of. The default value
is 1, only the immediate enclosing structure is broken out of.
How can I return the data which is presented inside of this foreach element, inside of my if statement, which comes after the initial foreach.
foreach ($arr as $line) {
print $line;
}
When we print $line it should return something like this.
Example 1
Example 2
Example 3
Example 4
I want to call each element from line, to be set inside of this if statement, but only if the statement contains a specific word.
$status_check = $_GET['status'];
if (strpos($status, 'online') !== false) {
print $line; // return all of the contents from the (foreach) here.
}
Based on your comments you need to return the data of the array outside of the foreach loop so you dont need to use one.
if (strpos($_GET['status'], 'online') !== false) {
print array_values($arr);
}
Will return:
Example 1
Example 2
Example 3
Example 4
Only if $_GET['status'] contains online
I am new in PHP and I have little problem. I have code like this:
$file = $_FILES['sel_file']['name'];
$chk_ext = explode(".",$file);
if(strtolower($chk_ext[1]) == "txt")
{
$filename = $_FILES['sel_file']['tmp_name'];
$handle = fopen($filename, "r");
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE)
{
$array = array( $data[0]);
foreach( $array as $value )
{
$number=$value;
}
$obj=new Sender("$number");
}
header("location:bulk.php?msg=send");
}
else
{
header("location:bulk.php?invalid=file");
exit();
}
$obj->Submit ();
Problem is that only last value comes out from text file in $obj=new Sender("$number");, please help me out.
fgetcsv() already return an array so: $array = array( $data[0]); just means that you only retrieve the first element of the array of fields which is $data.
In the foreach loop you should just replace the $array variable with $data.
The loop woould then look like this:
foreach( $data as $value )
{
$number=$value;
}
$obj=new Sender("$number");
means that for every element in $data, you hold it inside $number, loops again and put it again in $number overwriting it.
After the foreach loop the value of $number would be the last field of the row.
You should just put the line $obj=new Sender("$number"); inside the loop, so that every element of every row would be put in Sender.
No surprise. You loop over all the values, continually overwriting $number with the most recently retrieved value. When the loop exits, you end up with only the last one.
Probably you want something more like:
foreach($array as $value) {
$obj = new Sender($value);
}
your code also makes very little sense. You take an uploaded file, presumably CSV, read a line from it, extract the FIRSt value from that line. force the value into an array, then read back that ONE value in the array (the ONLY value in the array), and do something with it.
Even if your foreach wasn't overwriting the value, you still only have one single value to loop on anyways.
You are overwriting the contents of number each iteration. You can instead make number an array which stores each value at incrementing elements.
foreach( $array as $value )
{
$number[]=$value;
}
$obj=new Sender($number);
That's because you assign a new value to $number in each iteration. Either you need to append to that variable ($number .= $value) or you need to add it to an array ($number[] = $value).
I have created an array list with the following code:
<?php
$ids = array();
if (mysql_num_rows($query1))
{
while ($result = mysql_fetch_assoc($query1))
{
$ids["{$result['user_id']}"] = $result;
}
}
mysql_free_result($query1);
?>
Now, i need to read two elements from the array. The first is the current and the second one is the next element of array. So, the simplified process is the following:
i=0: current_element (pos:0), next_element (pos:1)
i=1: current_element (pos:1), next_element (pos:2)
etc
To do this, i have already written the following code, but i cant get the next element for each loop!
Here is the code:
if (count($ids))
{
foreach ($ids AS $id => $data)
{
$userA=$data['user_id'];
$userB=next($data['user_id']);
}
}
The message i receive is: Warning: next() expects parameter 1 to be array, string given in array.php on line X
Does anyone can help? Maybe i try to do it wrongly.
The current, next, prev, end functions work with the array itself and place a position mark on the array. If you want to use the next function, perhaps this is the code:
if (is_array($ids))
{
while(next($ids) !== FALSE) // make sure you still got a next element
{
prev($ids); // move flag back because invoking 'next()' above moved the flag forward
$userA = current($ids); // store the current element
next($ids); // move flag to next element
$userB = current($ids); // store the current element
echo(' userA='.$userA['user_id']);
echo('; userB='.$userB['user_id']);
echo("<br/>");
}
}
You'll get this text on the screen:
userA=1; userB=2
userA=2; userB=3
userA=3; userB=4
userA=4; userB=5
userA=5; userB=6
userA=6; userB=7
userA=7; userB=8
You get the first item, then loop over the rest and at the end of each loop you move the current item as the next first item ... the code should explain it better:
if (false !== ($userA = current($ids))) {
while (false !== ($userB = next($ids))) {
// do stuff with $userA['user_id'] and $userB['user_id']
$userA = $userB;
}
}
Previous answer
You can chunk the arrays into pairs:
foreach (array_chunk($ids, 2) as $pair) {
$userA = $pair[0]['user_id']
$userB = $pair[1]['user_id']; // may not exist if $ids size is uneven
}
See also: array_chunk()
I want to loop through an array with foreach to check if a value exists. If the value does exist, I want to delete the element which contains it.
I have the following code:
foreach($display_related_tags as $tag_name) {
if($tag_name == $found_tag['name']) {
// Delete element
}
}
I don't know how to delete the element once the value is found. How do I delete it?
I have to use foreach for this problem. There are probably alternatives to foreach, and you are welcome to share them.
If you also get the key, you can delete that item like this:
foreach ($display_related_tags as $key => $tag_name) {
if($tag_name == $found_tag['name']) {
unset($display_related_tags[$key]);
}
}
A better solution is to use the array_filter function:
$display_related_tags =
array_filter($display_related_tags, function($e) use($found_tag){
return $e != $found_tag['name'];
});
As the php documentation reads:
As foreach relies on the internal array pointer in PHP 5, changing it within the loop may lead to unexpected behavior.
In PHP 7, foreach does not use the internal array pointer.
foreach($display_related_tags as $key => $tag_name)
{
if($tag_name == $found_tag['name'])
unset($display_related_tags[$key];
}
Instead of doing foreach() loop on the array, it would be faster to use array_search() to find the proper key. On small arrays, I would go with foreach for better readibility, but for bigger arrays, or often executed code, this should be a bit more optimal:
$result=array_search($unwantedValue,$array,true);
if($result !== false) {
unset($array[$result]);
}
The strict comparsion operator !== is needed, because array_search() can return 0 as the index of the $unwantedValue.
Also, the above example will remove just the first value $unwantedValue, if the $unwantedValue can occur more then once in the $array, You should use array_keys(), to find all of them:
$result=array_keys($array,$unwantedValue,true)
foreach($result as $key) {
unset($array[$key]);
}
Check http://php.net/manual/en/function.array-search.php for more information.
if you have scenario in which you have to remove more then one values from the foreach array in this case you have to pass value by reference in for each:
I try to explain this scenario:
foreach ($manSkuQty as $man_sku => &$man_qty) {
foreach ($manufacturerSkus as $key1 => $val1) {
// some processing here and unset first loops entries
// here dont include again for next iterations
if(some condition)
unset($manSkuQty[$key1]);
}
}
}
in second loop you want to unset first loops entries dont come again in the iteration for performance purpose or else then unset from memory as well because in memory they present and will come in iterations.
There are already answers which are giving light on how to unset. Rather than repeating code in all your classes make function like below and use it in code whenever required. In business logic, sometimes you don't want to expose some properties. Please see below one liner call to remove
public static function removeKeysFromAssociativeArray($associativeArray, $keysToUnset)
{
if (empty($associativeArray) || empty($keysToUnset))
return array();
foreach ($associativeArray as $key => $arr) {
if (!is_array($arr)) {
continue;
}
foreach ($keysToUnset as $keyToUnset) {
if (array_key_exists($keyToUnset, $arr)) {
unset($arr[$keyToUnset]);
}
}
$associativeArray[$key] = $arr;
}
return $associativeArray;
}
Call like:
removeKeysFromAssociativeArray($arrValues, $keysToRemove);