Invalid argument in foreach

I’ve written a script to enable me to edit a simple TSV file and it seems to work except that having updated the file I get a PHP warning when it displays the data for editing.

First time through there is no warning; second and subsequent times I get the warning. If I press update without making any changes the “before” and “after” versions of the TSV file look identical in Notepad++ - but there is clearly some difference.

Here is my code:

function readtsvfile($file) {
  // Read tsv file into array
  $handle = fopen($file, 'r');
  while ( !feof($handle) )
    $array[] = fgetcsv($handle, 1024, "\t");
  fclose($handle);
  return $array;
}

$file = '../accounts-copy.tsv';

// values may have been modified - write updated file
if ( $_SERVER['REQUEST_METHOD'] == 'POST' ) {
  $data = readtsvfile($file);
  $handle = fopen($file, 'w');
  foreach ( $_POST['cell'] as $k1 => $row ) {
    $line = $data[$k1][0] . "\t";
    foreach ( $row as $k2 => $val )
      $line .= $val . "\t";
    fwrite($handle, rtrim($line).PHP_EOL);
  }
  fclose($handle);
  echo 'File updated', "\n";
}

// display file contents for editing
$data = readtsvfile($file);
echo '<form method="post">', "\n";
echo '<table>', "\n";
foreach ( $data as $k1 => $row ) {
  echo '  <tr>', "\n"; # line 34
  foreach ( $row as $k2 => $val ) {
    if ( $k2 == 0 )
      $val = htmlentities($val);
    if ( $k2>0 )
      echo '    <td><input type="text" name="cell[', $k1, '][', $k2, ']" value="', $val, '"></td>', "\n";
    else
      echo '    <td>', $val, '</td>', "\n";
  }
  echo '  </tr>', "\n";
}
echo '</table>', "\n";
echo '<input type="submit" value="Update">', "\n";
echo '</form>', "\n";

The warning is: Warning: Invalid argument supplied for foreach() in editcsv.php on line 34.

My unadulterated TSV file is attached (although I have had to change the extension to csv to upload).

accounts-copy.csv (490 Bytes)

Well, the obvious thing to do is logging (resp. looking, if you have remote debugging) what the variable in question actually contains.

1 Like

Thanks @Dormilich. I had been var_dumping $data and noticed no difference between “before” and “after”. Now when I var_dump $row AND look in the right place I see my edited file has an end of line at the end which the original doesn’t have.

The problem was an extra blank line being added to the end of the CSV file when it was updated

Try this:

<?php 
# ERRORS VERBOSE
  declare(strict_types=1);

  $tmp = 'ERROR_LOG.php';
  ini_set('error_log', $tmp );
  ini_set('log_errors', 'true');
  ini_set('html_errors', 'true');
  ini_set('track_errors', 'true');
  ini_set('display_errors', 'true');
  ini_set('display_startup_errors', 'true');
  error_reporting(-1);

# File Name
	$file = 'accounts-copy.tsv';
	$file = 'accounts-copy.csv'; // 

# values may have been modified - write updated file
	if ( $_SERVER['REQUEST_METHOD'] == 'POST' )
	{
		# fred($_POST, 'Just Posted');

	  $data 	= readtsvfile($file);
	  $handle = fopen($file, 'w');
	  foreach ( $_POST['cell'] as $k1 => $row )
	  {
	    $line = $data[$k1][0] . "\t";
	    foreach ( $row as $k2 => $val )
	    {	
	      $line .= $val . "\t";
	    }  

	    fwrite($handle, rtrim($line).PHP_EOL);
	  }
	  fclose($handle);
	  echo 'File updated', "\n";
	}

# display file contents for editing
	$data = readtsvfile($file);
	echo '<form method="post">', "\n";
	echo '<table>', "\n";
		foreach ( $data as $k1 => $row )
		{
		  echo '  <tr>', "\n"; # line 34
			  foreach ( $row as $k2 => $val )
			  {
			    if ( $k2 === 0 )
			    {
			      $val = htmlentities($val);
			      echo '<td>', $val, '</td>', "\n";
			    }else{  
			      echo '<td><input type="text" name="cell[', $k1, '][', $k2, ']" value="', $val, '"></td>', "\n";
			    }  
			  }#endif
		  echo '  </tr>', "\n";
		}#endforeach
	echo '</table>', "\n";
echo '<input type="submit" value="Update">', "\n";
echo '</form>', "\n";


//===============================================
function readtsvfile($file)
{
	$array = [];

  // Read tsv file into array
  $handle = fopen($file, 'r');
  while ( !feof($handle) )
  {	
  	$tmp = fgetcsv($handle, 1024, "\t");
  	if( $tmp ):
    	$array[] 	= $tmp;
    else:
    	echo '<h1> Yes we have NO fgetcsv(...) <br>' ; // fred($tmp)';
    		echo 'line: ' .__line__;
    		echo '<br>';
    	echo '</h1>';
    endif;
  }
    
  fclose($handle);
  return $array;
}

//===============================================
function fred($val, $title='')
{
	echo '<pre>'; echo $title .'<br>';
  	print_r($val); 
  echo '</pre>';
}

1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.