Link to home
Start Free TrialLog in
Avatar of Bruce Gust
Bruce GustFlag for United States of America

asked on

Why can't I get this file to show up correctly?

Here's my code:

class StoreCSV {

	public $csv;
	protected $data;
	
		public function importCSV()
		{
		
		if(empty($_POST['csv']))
		{
		print "there's no CSV file to look at!";
		return FALSE;
		}
		
		$this->csv=$_POST['csv'];
		//return $this->csv;
		
		}
		
		public function storeCSV()
		{
		global $mysqli;
		
		$this->csv_file_name="csv/$this->csv";
		//return $this->csv_file_name;
		
		$handle=fopen("csv/atlanta.csv", "r");
			
		}
}

Open in new window


No errors, which is great. But I'm hard coding the name and the location of the file at

$handle=fopen("csv/atlanta.csv", "r");

I want to code it as

$handle = fopen("$this->csv_file_name", "r");

When I try that, I get this error message:

 Warning: fopen(csv/): failed to open stream: No such file or directory in C:\wamp\www\sandbox\csv_store.php on line 38

Line 38 is the line that I'm referring to. In other words, the moment I replace "csv/Atlanta.csv" with $this->csv_file_name, I get an error message.

I can print $this->csv_file_name and it looks fine. What am I doing wrong that's producing the error?
Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

The error message makes reference to line 38, but there are not 38 lines in the code snippet posted here, so we know we are not looking at a true representation of the problem.  Please post the correct code snippet, thanks.
Avatar of Bruce Gust

ASKER

Sorry Ray!

The code snippet and the lines on the actual page are somewhat different, hence the disconnect.

In this case, the error is pointing to line 27. If you look at my code above, it currently reads "$handle=fopen("csv/atlanta.csv", "r");" THAT doesn't generate an error. But when I code that same line as:

$handle=fopen("$this->csv_file_name", "r");

...based on what I put together on line 24, that's when I get the error that says "failed to open stream."

I can "return" the correct directory and file name which you can see on line 25. I've got it commented out, but I was able to successfully return that value and it reads "csv/Atlanta.csv," just like I would want it to.

But when I replace "csv/Atlanta.csv" with $this->csv_file_name, I get the error and that's the problem I'm trying to solve.

Thanks for looking at it!
What do you get from var_dump($this) and var_dump($this->csv_file_name) ?
Avatar of Julian Hansen
A couple of things I noticed off the bat.

$handle = fopen("$this->csv_file_name", "r");

Open in new window


Not necessary to enclose in quotes - doesn't hurt but makes ore sense to do
$handle = fopen($this->csv_file_name, "r");

Open in new window


The thing to look at here is not the csv_file_name but how it is created

$this->csv_file_name="csv/$this->csv";

Open in new window


If $this->csv is not being set to "atlanta" then you are not comparing apples with apples.

Try this and see if it works

Default your $csv member variable to atlanta like so
class StoreCSV {

	public $csv = "atlanta.csv";

Open in new window

Test the code again - if it works then the problem is

a) Either you are not calling the importCSV member function
b) You are not posting any values to the page
c) You are posting values but they are the wrong ones.

I would work backwards from testing the default $csv value above and if that works moving back to the importCSV to make sure everything there is working.
This code worked for me.
class StoreCSV {

  public $csv = "atlanta.csv";
  protected $data;
  
    public function importCSV()
    {
      if(empty($_POST['csv']))
      {
      print "there's no CSV file to look at!";
      return FALSE;
      }
      
      $this->csv=$_POST['csv'];
      //return $this->csv;
    }
    
    public function storeCSV()
    {
      global $mysqli;
      
      $this->csv_file_name="csv/$this->csv";
      //return $this->csv_file_name;
      
//      $handle = fopen("csv/atlanta.csv", "r");
      $handle = fopen($this->csv_file_name, "r");
      if ($handle) {
        $result = fgets($handle);
        echo "Result {$result}\n";
        fclose($handle);
      }
    }
}

$fred = new StoreCSV();
$fred->storeCSV();

Open in new window

Gentlemen!

Both of you seem to be suspecting the same thing. I've been playing with it right up to the point where I'm ready for another set of eyes and here's what I've been able to conclude:

$this->csv=$_POST['csv'] isn't yielding a result. That's why I keep getting the error message that I am.

Below is my code in its entirety. I changed the $_POST['csv'] to $_POST['csv_name'] to see if that made any difference, which it did not, but should you notice that difference, I wanted to provide some context.

Below the code, is a screenshot of the results. So, here's the equivalent to looking over my shoulder...

<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
echo '<pre>';

include("carter.inc");
$cxn = mysqli_connect($host,$user,$password,$database)
or die ("couldn't connect to server");
date_default_timezone_set('America/Chicago');
$mysqli = new mysqli($host, $user, $password, $database);

class StoreCSV {

	public $csv;
	protected $data;
	
		public function importCSV()
		{
		
		if(empty($_POST['csv_name']))
		{
		print "there's no CSV file to look at!";
		return FALSE;
		}
		else
		{
		print "hello";
		}
		
		$this->csv=$_POST['csv_name'];
		//return $this->csv;
		var_dump($this->csv);
		print "hello";
		}
		
		public function storeCSV()
		{
		global $mysqli;
		
		$this->csv_file_name="csv/$this->csv";
		//return $this->csv_file_name;
		var_dump($this->csv_file_name);
		$handle=fopen($this->csv_file_name, "r");
			
		}
}

?>

<!DOCTYPE html>
<html lang="en">
<head>
<title>CSV Upload</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>

<body>

<?php
$results = new StoreCSV;
//echo $results->importCSV();
//echo $results->storeCSV();
?>

</body>
</html>

Open in new window


As an aside, when I do echo $_POST['csv_name'], I get "atlanta.csv," so we're getting spark, we're just not getting ignition.

Also, I was curious as to what the purpose behind defining properties was, as far as having $csv set up as a public property when I refer to it as $this->csv throughout my class. Could I not get by without defining it as a property?

Very basic question, no doubt, but I want to be able to explain this to others at some point and I wouldn't be able to explain the purpose of those properties if I was asked. So, why do those need to be there?

Thanks!
screenshot.png
The code posted is not what is important.

What we need to see is the code that is POSTING to this page.

if you add
$_POST['csv'] = 'atlanta.csv';

Open in new window

just before
$results = new StoreCSV;

Open in new window

Does it work?
Here's the code that is feeding the page where my problem resides:

<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
echo '<pre>';

include("carter.inc");
$cxn = mysqli_connect($host,$user,$password,$database)
or die ("couldn't connect to server");
date_default_timezone_set('America/Chicago');
$mysqli = new mysqli($host, $user, $password, $database);

class MyCSV {

	public $csv;
	protected $header;
	protected $data;
	
	public function __construct($dir='csv')
	{
	include("error_key.php");
	
	if(empty($_FILES['csv']['name']))
		{
		print "there's nothing to upload, man!";
		return FALSE;
		}
			
	$this->error_code=$_FILES["csv"]["error"];
	if($this->error_code)
		{
		trigger_error($errors[$this->error_code], E_USER_ERROR);
		}
		
	$this->csv=getcwd(). DIRECTORY_SEPARATOR . $dir . DIRECTORY_SEPARATOR . $_FILES['csv']['name'];
	
	if (move_uploaded_file($_FILES['csv']['tmp_name'], $this->csv))
		{
		return TRUE;
		}
		else
		{
		trigger_error("Didn't get anything moved to $this-csv", E_USER_ERROR);
		}
		
	}
	
	public function getFile()
	{
	return $this->csv;
	}
	
	public function getHeader()
	{
		if($this->header) return $this->header;
		
		$this->fpr = fopen($this->csv, 'rb');
		if(!$this->fpr) trigger_error("Unable to open $this->csv for 'rb'", E_USER_ERROR);
		$this->header=fgetcsv($this->fpr);
		if(!$this->header) trigger_error("Unable to read $this->csv", E_USER_ERROR);
		return $this->header;
	}
	
	public function getData()
	{
	if($data=fgetcsv($this->fpr)) return $data;
	return FALSE;
	}

}

function TableInfo()
{
	global $mysqli;
	
	$sql = "show columns from verizon";
	$query = $mysqli->query($sql);
	
	if(!$query)
	{
	$error = $mysqli->errno.': '.$mysqli->error;
	trigger_error($error, E_USER_WARNING);
	}
	
	$data_count=mysqli_num_rows($query);
	
	if($data_count==0)
	{
	trigger_error("you don't have any column names", E_USER_WARNING);
	}
	//return $data_count;
	
	while($show_columns=$query->fetch_object())
	{
	$the_columns[]=$show_columns->Field;
	}
	return $the_columns;
}

echo '</pre>';
?>

<!DOCTYPE html>
<html lang="en">
<head>
<title>CSV Upload</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>

<body>

<table border="0"><form action="csv_store.php" method="Post">
	<tr>
		<td class="vivian">
		Your File
		</td>
		<td class="vivian">
		Target File
		</td>
	</tr>
	<?php 
	$the_count=1;
	$results = new MyCSV;
	$the_csv=$results->getFile();
	$the_header=$results->getHeader();
	//print_r ($the_header[0]);
	//$results_count=count($the_header);
	
	$columns = TableInfo();
	unset($columns[0]);
	//$column_count=count($columns);
	//echo $column_count;
	
	foreach ($the_header as $value)
	{
	echo "<tr><td><input type=\"text\" size=\"35\" value=\"$value\" name=\"column_$the_count'\"></td>";
	echo "<td>";
	?>
		<select name="select_name_<?php echo $the_count; ?>">
		<option></option>
		<?php
		foreach($columns as $row)
		{
		echo "<option>$row</option>";
		}
		?>
		</select>
		</td>
	</tr>
	<?php
	$the_count=$the_count+1;
	}
	?>
	<tr>
		<td colspan="2" style="text-align:center;"><input type="hidden" name="csv_name" value="<?php echo $_FILES['csv']['name']; ?>">
		<input type="submit" value="submit">
		</td>
	</tr>
</table></form>

</body>
</html>

Open in new window


And Julian, to answer your question, "No." Adding $_POST['csv_name'] doesn't alter the end result (I changed the name of the field).
Ok the problem is your class is the same name as the function you are trying to call i.e.

class StoreCSV {
   function StoreCSV()

Open in new window


In PHP the constructor is defined either by

function __constructor()

Open in new window


Or

function CLASSNAME

Open in new window


Because the StoreCSV function is the same name as the class it is being invoked when you instantiate the class i.e.

$results = new StoreCSV();

Open in new window


Because this is before you have called the importCSV function $this->csv_name is not defined.

To fix - change the storeCSV() function name OR the class name to something different.
I changed the $_POST['csv'] to $_POST['csv_name'] to see if that made any difference,...
Sigh.  How about var_dump($_POST) ?  And var_dump($_FILES) ?

Or maybe just tell us in plain language what you're trying to do, step-by-step.  Where does the data come from, where do you want it to go. etc.  We can probably give you tested and working code examples, if you'll give us some test data.  This will almost certainly be a faster path to success than having us try to guess what could be wrong with your code.
That did it, Julian!

But tell me why when I do this:

$results = new StoreCSV;
//echo $results->importCSV();
echo $results->loadCSV();

I get an error. It's the same error in that "$this->csv" is not showing up anywhere.

But when I do this:

$results = new StoreCSV;
echo $results->importCSV();
echo $results->loadCSV();

...I don't get an error and "$this->csv" shows up just fine. Why do I have to specify importCSV() in order for loadCSV to fire correctly?
loadCSV - have not seen  that in your code posted so far.

You should get the error regardless - why you are not I can't say - given that you are calling loadCSV and it does not appear in any of the code posted so far I am guessing there is more code than you have posted.
Sorry, Ray!

I did do the var_dump like you suggested and it was in the aftermath of seeing those results that led me to understand that I wasn't getting $this->csv, although it was being accurately posted to the page. I didn't articulate what those results were just because I figured it was the problem that you were wanting to define rather than just the variables that were published.

When I did var_dump($this-csv), I got nothing. When I did var_dump($this-csv_file_name) I got 'csv/' and that's it. So, it's the $this->csv thing that's clogging the pipes.

As far as what I'm trying to do, the scaffolding that you see is the beginning of a project where my user is uploading a csv file that has column headings that don't necessarily match the fields in the database the info is getting ready to be uploaded to.

The page prior to the one you're trying to decipher on my behalf gives the user the chance to match their fields with those that are in the database. After they've done that, they hit "submit" and the hidden field "csv_name" publishes the name of the file to the page you're looking at now where I'm getting ready to parse it into the database.

The dilemma right now is the fact that I can't even pop the hood on the incoming csv file because I can't "see" it, despite the fact that there is accurate data coming from the previous page (Atlanta.csv), but my function isn't seeing it and I don't know why.
loadCSV is the new name of the function that was competing originally with the name of the class - the thing that you pointed out. Here's the whole code:

<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
echo '<pre>';

include("carter.inc");
$cxn = mysqli_connect($host,$user,$password,$database)
or die ("couldn't connect to server");
date_default_timezone_set('America/Chicago');
$mysqli = new mysqli($host, $user, $password, $database);

class StoreCSV {

	public $csv;
	protected $data;
	
		public function importCSV()
		{
		
		if(empty($_POST['csv_name']))
		{
		print "there's no CSV file to look at!";
		return FALSE;
		}
		
		
		$this->csv=$_POST['csv_name'];
		//return $this->csv;
		//var_dump($this->csv);
		print "hello";
		}
		
		public function loadCSV()
		{
		global $mysqli;
		
		$this->csv_file_name="csv/$this->csv";
		//return $this->csv_file_name;
		var_dump($this->csv_file_name);
		$handle=fopen($this->csv_file_name, "r");
			
		}
}

?>

<!DOCTYPE html>
<html lang="en">
<head>
<title>CSV Upload</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>

<body>

<?php
//$_POST['csv_name']='atlanta.csv';
$results = new StoreCSV;
//echo $results->importCSV();
echo $results->loadCSV();
?>

</body>
</html>

Open in new window

I get a Warning for both
$results = new StoreCSV;
//echo $results->importCSV();
echo $results->loadCSV();

Open in new window

And
$results = new StoreCSV;
echo $results->importCSV();
echo $results->loadCSV();

Open in new window

In the second case I get the output message
there's no CSV file to look at!
Which is to be expected because nothing has been posted to this form.
If I do this
$_POST['csv_name']='atlanta.csv';
$results = new StoreCSV;
echo $results->importCSV();
echo $results->loadCSV();

Open in new window

I don't get the output error message or a warning.

All is as expected - the importCSV is dumping its error message because there is nothing in $_POST - when you comment it out (or add the $_POST variable) - the message obviously goes away.
As far as what I'm trying to do, the scaffolding that you see is the beginning of a project where my user is uploading a csv file that has column headings that don't necessarily match the fields in the database the info is getting ready to be uploaded to.
So as I understand it, the steps would be more-or-less like this:

1. Upload a CSV file (this is in the "form" script)
2. Move_Uploaded_File() to a storage location (this and subsequent would be in the "action" script)
3. Determine the coordination of the CSV column headings with the DB table column names*
4. Prepare INSERT statement template(s)
5. Iterate over the contents of the CSV file to insert the information into the DB table.

Is that about right?

*This is the part that will require some design thought.  It would be much easier to get the process going if the CSV headers were in the same order as the DB columns, and if the CSV headers matched, in a case-sensitive way, the DB column names!  Much easier!
Gentlemen, I got it to work, but I would welcome you're assessment in order to ensure that what I've done represents good programming and not just something that's been duct taped together.

Julian, your last post inspired me to reconsider the way my posted data was being interpreted by my function. I knew for a fact that the CSV data was being posted, having checked that earlier. So, when I read your post that suggested there wasn't anything being posted, I determined to revamp the way that posted data was being "seen" by my function.

Ray, your counsel, as far as inserting some "var_dumps" to view what my code was perceiving led me to a frustrating impasse in that I could echo $_POST['csv_file'] and see the results in the context of my HTML, but my class / function wasn't recognizing it.

So, I chose to treat the posted data as a variable that I passed into my function when I called it, so it looked like this:

First, here's my class / function:

class StoreCSV {

	public $csv;
	protected $data;
	
		public function importCSV($incoming_csv) //here's where I made my change
		{
			if(empty($incoming_csv))
			{
			print "there's no CSV file to look at!";
			return FALSE;
			}
			else
			{
			$this->csv=$incoming_csv;
			}
		}
		
		public function loadCSV()
		{
		global $mysqli;
		$this->csv_file_name="csv/$this->csv";
		var_dump($this->csv_file_name);
		$handle=fopen($this->csv_file_name, "r");
		}
}

Open in new window


...and here's the HTML portion:

$results = new StoreCSV;
$results->importCSV($_POST['csv_name']);
echo $results->loadCSV();

Open in new window


On the line where I had $results->importCSV(), I replaced that with $results->importCSV($_POST['csv_name']) and at that point, there were no errors and on my page I could see "string 'csv/atlanta.csv' (length=15)" from the line with my loadCSV() function where I did var_dump($this->csv_file_name);

Now, here's where I would like you to either correct me or affirm me as far as my attempt to explain what was going on and why my change made the difference.

You treat posted variables differently in an OOP dynamic when compared to a Procedural approach. With a Procedural methodology, you're asserting the posted data simply by writing it directly into your code. When you're using posted data in the context of a function, you still have to be just as intentional in inserting it into your syntax, but you do so by passing it along as a variable when you call that function.

So, if you have a function like this, for example:

public function importCSV()
{
$this->csv=$_POST['csv'];
}

...and you call it in your HTML like this:

$results=importCSV();

You're not going to get anything. The function is dormant until you call it. And when do call it, the "posted" dynamic has most likely come and gone, so you're asking your function to look for something that doesn't exist.

On the other hand, when you write it like this:

public function importCSV($incoming_csv)
{
$this->csv=$incoming_csv;
}

And call it in your HTML like this:

$results=importCSV($_POST['incoming_csv'];

Now you've given your code something to chew on and you're good to go.

Is that correct?

BTW: Ray, I just saw you posted something just as I was getting ready to post this so if this completely off or redundant, it's because our posts passed each other. There you go...
SOLUTION
Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
You're not going to get anything. The function is dormant until you call it. And when do call it, the "posted" dynamic has most likely come and gone, so you're asking your function to look for something that doesn't exist.
No - the globals persist throughout the lifetime of the script
Consider this code
<?php

class Test
{
  function testPost()
  {
    echo "<pre>" . print_r($_POST, true) . "</pre>";
    
    if (!empty($_POST['test'])) {
      echo "The value of the [test] parameter is {$_POST['test']}<br/>";
    }
    else {
      echo "The [test] parameter is missing from the POST array<br/>";
    }
  }
}
?>
<!doctype html>
<html>
<head><title>Test</title></head>
<body>
<?php
if ($_POST) {
  $x = new Test;
  $x->testPost();
}
?>
Good Form
<form method="POST">
  CSV Name <input type="text" name="test" /><br/>
  <input type="submit" value="Go" />
</form>
Bad form
<form method="POST">
  CSV Name <input type="text" name="badtest" /><br/>
  <input type="submit" value="Go" />
</form>

</body>
</html>

Open in new window

Working sample here http://www.marcorpsa.com/ee/e065.php
Explanation to follow
What you will see in this sample is a page with two forms (Good and Bad)

The good form posts a variable called 'test'
The second form posts a variable called 'badtest'

In the Test class we invoke the testPost  method and test for the existence of the required POST variable - if it exists we print a success message - if it does not a failure message.

We instantiate the test class inside and if statement that checks whether or not anything has been posted to the form - we don't want to dump messages while in the data acquisition phase.

As you can see from the sample - that the $_POST is correctly accessible in the testPost function and that if data is passed from the form to the page correctly it is picked up in the testPost method.

Where you access the $_POST is immaterial - providing you have not overwritten it earlier in your script it should be available and in tact until your script dies a natural death.
Alright, boys!

I've been able to successfully identify the posted data using your assistance and the "winning" code is below:

<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
echo '<pre>';

include("carter.inc");
$cxn = mysqli_connect($host,$user,$password,$database)
or die ("couldn't connect to server");
date_default_timezone_set('America/Chicago');
$mysqli = new mysqli($host, $user, $password, $database);

class StoreCSV {

	public $csv;
	protected $data;
	
		public function importCSV()
		{
		
			if(empty($_POST['csv_name']))
			{
			print "there's no CSV file to look at!";
			return FALSE;
			}
			else
			{
			$this->csv=$_POST['csv_name'];
			return $this->csv;
			}
		}
		
		public function loadCSV()
		{
		global $mysqli;
		
		$this->csv_file_name="csv/$this->csv";
		//return $this->csv_file_name;
		var_dump($this->csv_file_name);
		$handle=fopen($this->csv_file_name, "r");
			
		}
}

?>

<!DOCTYPE html>
<html lang="en">
<head>
<title>CSV Upload</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>

<body>

<?php
//$_POST['csv_name']='atlanta.csv';
$results = new StoreCSV;
echo $results->importCSV();
echo $results->loadCSV();
?>

</body>
</html>

Open in new window


When I run this page, I get:

atlanta.csv

string 'csv/atlanta.csv' (length=15)

Yay! Woo-hoo! Diet Pepsis all around!

But, Ray, back to your frustration as far as "wandering..."

The original question was based on the fact that my code wasn't "seeing" the posted data. When I do this:

<?php
$results = new StoreCSV;
echo $results->importCSV();
echo $results->loadCSV();
?>

I get total victory!

But when I do this:

<?php
//$_POST['csv_name']='atlanta.csv';
$results = new StoreCSV;
echo $results->loadCSV();
?>

I get what you see below...

User generated image
So WHY - when I can run this page with:

<?php
$results = new StoreCSV;
echo $results->importCSV();
echo $results->loadCSV();
?>

...and get everything I need to proceed. Why does everything explode in a twisted ball of metallic flame the moment I eliminate "echo $results->importCSV;?"

I would think that if I can confirm the fact that $this->csv=$_POST['csv_name'] exists, then that variable would be recognized in the next function in my Class when I say that the file I'm looking for is going to be in "csv/$this->csv." I've established $this->csv, right? I can see it. Yet, it would appear that if I don't "call" that function like this:

$results = new StoreCSV;
echo $results->importCSV();
echo $results->loadCSV();

...then I get an error because $this->csv has gotten lost somewhere between defining it as $this->csv=$_POST['csv_name'] and $this->csv_file_name="csv/$this->csv"; By the time I get to $this->csv_file_name, $this->csv file has been lost somehow.

That's the bottom line dilemma. I can see the posted data, but the variable that captures that in the first function doesn't show up when I go to call that same variable in my second function. Why?
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I don't know, so much of this is just confusing to me and there are fragments of the code all over the place.  I just can't follow it.  We really need the SSCCE all in one place to give you good answers.  

Have a look at these two statements, which look a lot alike but are meaningfully different in practice.

echo $results->importCSV();
echo $results->importCSV;


The first statement makes a function-call to the importcsv() method in the class that was used to instantiate the results object.  The echo statement will write the return value from that function to the browser output stream.  

The second statement is a simple echo, using the importCSV property of the $results object, which is assumed to be a string.  If it's not a string, PHP will try to convert it to a string for you, perhaps with unwanted results.

Suggest you add this line to the top of all of your PHP scripts:

error_reporting(E_ALL);

Anyway, I've done the best I can here.  Time to move on.
As always, thanks for your time and willingness to share your expertise. The bottom line is that I was using a function to define a variable and then assuming that same variable was going to be seen by subsequent functions without having to call them individually. I went back and used construct to define $this->csv and it was then that things worked the way I hoped.

Thanks again for your time and patience!
You are welcome - good luck with your project.