multiple data entry?

rafiq009

New Member
Messages
15
Reaction score
0
Points
1
hi, i am new in php world. i am trying to write a simple php script that retrieve some information from one table and store them with additional information in another table. i wrote a code that can store single entry, but when i try to store multiple information at once i am facing problem. please help me.

my sample database:
1. product(id,name,company)

id name company
100 monitor abc
201 monitor xyz
102 mouse abc
201 mouse xyz
103 keyboard abc

2. store(id,name,price,quantity)

Now i would like to find the product which company name is ‘abc’ then add their price and quantity and store them in store table

here is my code:

<form method="post" action="update_action.php">
<TABLE >
<?php

echo"<tr>
<td ><strong>ID</strong></td>
<td ><strong>Name</strong></td>
<td ><strong>Company</strong></td>
<td ><strong>Price</strong></td>
<td ><strong>Quantity</strong></td>
</tr>";
$sql=mysql_query("select * from product where company='abc'");
while($db=mysql_fetch_array($sql)){
echo"<tr>
<td>$db[id]</td>
<td>$db[name]</td>
<td>$db[company]</td>
<td><input name=price[$db[id]] type=text ></td>
<td><input name=quantity[$db[id]] type=text ></td>
</tr>";
}
echo"<tr>
<td colspan=5 align=center><input type=submit name=Submit value=Submit></td>
</tr>";

?>

now please tell me what will be my code in update_action.php
 

smithee

New Member
Messages
45
Reaction score
2
Points
0
Hi rafiq009... first of all there are some smaller things to point out in your code, such as not closing the table tag, and considering using a stronger and more secure MySQL database handlers such as PDO. Anyway, I'll just concentrate on the problem you're wanting to sort out now.

Code:
<form method="post" action="update_action.php">

By using post as your choice of passing form data into update_action.php, you can access these values by using $_POST['name'], where name is the name of the form object's name that holds the value you're after. For example:

PHP:
<td><input name=price[$db[id]] type=text ></td>

One of the form names will be "price[100]", so then you can get its value by using $_POST['price[100]'] in update_action.php. You can actually use a loop on that page, but you'll need to gain a reference to that previous database information, so back in that original file where the form is, include this:

PHP:
<input name=company type=hidden value=abc>


Finally, in update_action.php, you can now do this:
PHP:
$sql=mysql_query("select * from product where company=\'$_POST['company']\'");
$values = "";
while($db=mysql_fetch_array($sql)){
$id = $db['id'];
$values .= "($id,\'$db['name']\',$_POST['price[$id]'],$_POST['quantity[$id]']),";
}
mysql_query("INSERT INTO store (id,name,price,quantity) VALUES ($values))";

That should do the following:

  1. Fetch the data from the product table where the company matches the one specified in the previous code.
  2. Create a new empty variable called "values".
  3. Cycle through each row of data retrieved from the product table, and whilst it does that, it:
    • Sets the variable "id" to be the id currently initialised
    • Builds the second-half of an SQL to be used by pending all the values to be inserted into the "values" variable
    • Repeats itself again until all the values are initialised
  4. Execute an INSERT query which inserts data into the table store, and includes the values compiled earlier on.

Make sure you remember to include the usual database object initiators at the beginning, so your code knows where to look!

Any other problems with this, or anything you're unsure of, give us a shout!
 

rafiq009

New Member
Messages
15
Reaction score
0
Points
1
hi smithee, thanks for your detail suggestion. now my first page is like this
PHP:
$sql=mysql_query("select * from product where company='abc'");
	while($db=mysql_fetch_array($sql)){
		echo"<tr>
			<td>$db[id]</td>
			<td>$db[name]</td>
			<td><input name=company type=hidden value='abc'>$db[company]</td>
			<td><input name=price[$db[id]] type=text ></td>
			<td><input name=quantity[$db[id]] type=text ></td>
		</tr>";
	}
	echo"<tr>
		<td colspan=5 align=center><input type=submit name=Submit value=Submit></td>
	</tr>";

and update_action.php page is like:
PHP:
$sql=mysql_query("select * from product where company=\'$_POST['company']\'"); 
$values = ""; 
while($db=mysql_fetch_array($sql)){ 
$id = $db['id']; 
$values .= "($id,\'$db['name']\',$_POST['price[$id]'],$_POST['quantity[$id]']),"; 
} 
mysql_query("INSERT INTO store (id,name,price,quantity) VALUES ($values))";

after executing this, error shows on first line. then i modify it like this.
PHP:
$company=$_POST['company'];

	$sql=mysql_query("select * from product where company='$company'");
	$values = "";
	while($db=mysql_fetch_array($sql)){
	$id = $db['id'];
	$name = $db['name'];
	$price = $_POST['price[$db[id]]'];
	$quantity = $_POST['quantity[$db[id]]'];
	$values .= "($id,$name,$price,$quantity),";
	}
	mysql_query("INSERT INTO store (id,name,price,quantity) VALUES ($values)");

Yet i have problem here. store table is still empty and i found that $price contain nothing. May be i made any mistake in first page. can you please tell me how to solve this.
 

smithee

New Member
Messages
45
Reaction score
2
Points
0
One mistake I have spotted is mis-using quotes. When you use single quotes, everything is seen as a string, even if it appears to be a variable. When you use double quotes, everything that is not seen as a PHP variable will be displayed as is: http://v1.jeroenmulder.com/weblog/2005/04/php_single_and_double_quotes.php

Also you've specified a sepatare $id variable within the loop.

So this:

PHP:
$price = $_POST['price[$db[id]]'];

...should be this:

PHP:
$price = $_POST["price[$id]"];

...or this:

PHP:
$price = $_POST['price['.$id.']'];

I've put that in myself and didn't notice, so my fault that is (late night then I suppose!)

That will solve the empty $price, but I'm still a bit confused as to why this won't add to the store table. Echo the mysql_query command with the INSERT, and see what it outputs. If it returns true, 1, or -1, then it's able to insert the values, so there will be something up with the variables. If it returns false or 0, then it can't due to one or more problems:

  • It cannot connect to the database
  • It cannot find the table you're after
  • The values you want to import are not of the right type for the fields
  • The table is restricted from outside edits

If it does return false, then make use of mysql_error():

PHP:
if (!mysql_query("INSERT INTO store (id,name,price,quantity) VALUES ($values)")) echo mysql_error();
 

rafiq009

New Member
Messages
15
Reaction score
0
Points
1
Thanks again. tried this

PHP:
$price = $_POST["price[$id]"];

and this

PHP:
$price = $_POST['price['.$id.']'];

still $price is blank. database connection is ok as well as table name.

and i use this
PHP:
if (!mysql_query("INSERT INTO store (id,name,price,quantity) VALUES ($values)")) echo mysql_error();

and found this:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line

i think there is something wrong in (may be the last comma)

PHP:
$values .= "('$id','$name','$price','$quantity'),";

but i dont know what is happening with $price
 

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
The code is vulnerable to SQL injection. Switch to PDO and prepared statements. Prepared statements will also be more efficient, since you're repeatedly executing the same query with different values. If you want a tutorial, try "Writing MySQL Scripts with PHP and PDO".

Switching from assembled statements to prepared statements also makes the query more readable, since the SQL statement isn't scattered in pieces all around the PHP code. The query you're trying to execute (when assembled) is:
Code:
INSERT INTO store (id,name,price,quantity) 
  VALUES ((${db['id']},${db['name']},${_POST["price[${db['id']}]"]},$_POST["quantity[${db['id']}]"]),)
Not only does the final comma cause problems, so do the extra parentheses, lack of quotes around the values and improper array indexes. Since the form inputs are named with array syntax (e.g. "price[$db[id]]"; the HTML elements should also have double quotes around the attribute values), certain $_POST elements are arrays and should be accessed as such (e.g. "$_POST[price][$db['id']]").

Since the values you're inserting include what is presumably a unique column, your code should handle duplicates with the ON DUPLICATE KEY UPDATE clause.

The SELECT in update_action.php is an unnecessary use of resources. Instead, include hidden (or read-only) fields in the form.

Unless the "store" table is supposed to replace the "products" table, repeating data in each is premature denormalization. You'll have to do extra work to keep the two tables synchronized. You could have a "product" table (product (id, name, description)) storing information about each product and an "inventory" table (inventory (product_id, co, price, quantity)) storing what each company has in stock, and how much it charges.

Instead of using SELECT *, select only the fields you need.

Outputting DB error messages is all right for quick-and-dirty debugging, but you should never do it in production code anyplace that a non-administrator can access, as it discloses too much information. Be warned that scaffolding (debugging code) has a tendency to be left in place longer than it needs to and might show up in production code; it's safest to avoid quick-and-dirty techniques and log the error where only an admin can read it.

In some library script, part of a display module:
PHP:
<?php
  function echoProductField($product, $field, $type="text") {
    ?><input name="product[<?php echo $product['id'], '][', $field; ?>]" value="<?php echo $product[$field]?>" type="?<php echo $type; ?>"/>
    <?php
    switch ($type) {
    case 'radio':
    case 'checkbox':
    case 'hidden':
      <label for="product[<?php echo $product['id'], '][', $field; ?>]"><?php echo $product[$field]; ?></label>
      <?php
      break;

    default:
      break;
    }
  }

Form page:
PHP:
<?php

  try {
    $getCoProducts = $db->prepare("SELECT id, name, company AS co FROM product WHERE company = ?")
    $products = $db->execute(array('abc'));
  ?>
  <form method="post" action="update_action.php">
    <table>
      <tr>
        <th>ID</th><th>Name</th><th>Company</th><th>Price</td><th>Quantity</th>
      </tr>
      <?php foreach ($products as $product): ?>
        <tr>
          <td><?php echoProductField($product, 'id', 'hidden'); ?></td>
          <td><?php echoProductField($product, 'name', 'hidden'); ?></td>
          <td><?php echoProductField($product, 'co', 'hidden'); ?></td>
          <td><input name="product[<?php echo $product['id']; ?>][price]" value="" /></td>
          <td><input name="product[<?php echo $product['id']; ?>][quantity]" value="" /></td>
        </tr>
      <?php endforeach; ?>
    </table>
    <input type="submit" />
  </form>
} catch (PDOException $error) {
  error_log($error);
  ?>
  <div class="error">There was an internal error. It's been logged, and we'll look into it. Please give us some time to fix it and try again later.</div>
  <?php
}

update_action.php:
PHP:
<?php
$fields = array(
    'id' => array('type' => 'hidden', 'label' => 'ID'),
    'name' => array('type' => 'hidden', 'label' => 'Name'),
    'co' => array('type' => 'hidden', 'label' => 'Company'),
    'price' => array('type' => 'text', 'label' => 'Price'),
    'quantity' => array('type' => 'text', 'label' => 'Quantity'),
);

try {
  $insert = $db->prepare('INSERT INTO inventory (`id`, `company`, `price`, `quantity`)
          VALUES (:id, :co, :price, :quantity)
          ON DUPLICATE KEY UPDATE `company`=:co, `price`=:price, `quantity`=:quantity');
  $failed = array();
  foreach ($_POST['product'] as $product) {
      $productData = array();
      foreach ($product as $key => $val) {
        $productData[':' . $key] = $val;
      }
      if (False === $insert->execute($productData)) {
        $failed[] = $product;
      }
  }
} catch (PDOException $error) {
  error_log($error);
  ?><div class="error">There was an internal error. It's been logged, and we'll look into it. Please give us some time to fix it and try again later.</div><?php
}
if ($failed) {
  // include information about what user can do to correct the failure.
  ?><p>Insertion of the following products failed:</p>
  <form action="<?php echo $_SERVER['REQUEST_URI']; ?>" method="POST">
    <table>
      <tr>
        <?php foreach ($fields as $field): ?>
          <td><?php echo $field['label']; ?></td>
        <?php endforeach; ?>
      </tr>
      <?php foreach ($failed as $product): 
        ?>
        <tr>
          <?php foreach ($fields as $field => $info): ?>
            <td><?php echoProductField($product, $field, $info['type']); ?></td> 
          <?php endforeach; ?>
        </tr>
      <?php endforeach; ?>
    </table>
    <input type="submit" />
  </form>
  <?php
}

Many additional tasks need to be added to the sample, such as input validation (hidden fields are cosmetic, rather than providing security).

Database access, the display logic and the domain logic should be separated into different modules, but that can be taken care of later. To ease this, you can create a class to hold inventory information for a product and a company, and replace echoProductField with a view class that can display form inputs.
 
Last edited:

smithee

New Member
Messages
45
Reaction score
2
Points
0
You're right that the INSERT query problem has got to do with that last comma in $value, but that's required to separate each row of data. What I haven't counted for is that it will still produce it at the very end, when there shouldn't be one. That last comma can easily be removed by using substr().

Also this line:

PHP:
$values .= "('$id','$name','$price','$quantity'),";

... should be:

PHP:
$values .= "($id,'$name',$price,$quantity),";

... as $name is the only one that is a string in the query, so quotation marks must be used to represent this in the MySQL script. The rest are numbers, so they must not have them.

Another thing I've noticed about that last query are the brackets around $values... this is not to be used as wrapped brackets already exist around each row set. Sorry about that!

Mentioning the above, add this code above the INSERT query:

PHP:
$values = substr($values,0,-1);

This will re-save all but the last character of $values, and that last character is the last comma.

Finally, the INSERT query should now look like this:

PHP:
mysql_query("INSERT INTO store (id,name,price,quantity) VALUES $values");

Now for the empty $price... I've had to quickly use this script myself to find out what the problem was, as I really was scratching my head on this one! It wasn't until I entered print_r($_POST); into the script. This allowed me to show ALL the variables that the form has posted, and this is what appeared:

Code:
Array ( [company] => abc [price] => Array ( [100] => 25 [102] => 15 [103] => 5.99 ) [quantity] => Array ( [100] => 100 [102] => 50 [103] => 10 ) [Submit] => Submit )

And to make it even more clearer, I looked at the source, and it showed this:

Code:
Array
(
    [company] => abc
    [price] => Array
        (
            [100] => 25
            [102] => 15
            [103] => 5.99
        )
 
    [quantity] => Array
        (
            [100] => 100
            [102] => 50
            [103] => 10
        )
 
    [Submit] => Submit
)

How you've put together the code on the first page has forced the price and quantity variables to become arrays! Now knowing that, this should work (as it does on my server!):

PHP:
<?php

$company=$_POST['company'];
$sql=mysql_query("select * from product where company='$company'"); 
$values = ""; 
$price = $_POST["price"];
$quantity = $_POST["quantity"];
while($db=mysql_fetch_array($sql)){ 
	$id = $db['id'];
	$name = $db['name']; 
	$values .= "($id,'$name',$price[$id],$quantity[$id]),"; 
} 
$values = substr($values,0,-1);
mysql_query("INSERT INTO store (id,name,price,quantity) VALUES $values");
	
?>

Notice I've removed the $price and $quantity from the loop, and made it directly equal to $_POST["price"] and $_POST["quantity"] respectively, as they actually return arrays, and not single values. Then they can be accessed via $price[$id] and $quantity[$id].

Can I also point out from what I've said right at the beginning of this thread... I've only aimed to solve the problem you're having. To improve on it further, the form page needs tidying up by properly closing tags, consider using header tags instead of implying STRONG in each cell of the top row, and switching to a much more secure and solid database object handler. PDO's a good one, and I would know as I use it myself!!


EDIT:

Where did you come from misson?! I must admit your solution is far superior comparing to mine, but I was only here to solve the problem.

rafiq009, for a quick fix to get a working solution where you can probably understand it more, use the code I've suggested. But by the looks of things misson favours PDO as well, and has also provided a robust piece of pretty much "perfection"! So in the long run, his code will prove far more effective. But don't just whack it in, study it and see how it works... you'll be surprised at what you can learn!
;)
 
Last edited:

rafiq009

New Member
Messages
15
Reaction score
0
Points
1
Thanks both of you. Your suggestions and references were very much helpful. I learn so many new things from you. Both of you told about PDO. I am reading this topic. Its new to me, so i need time. Now everything is ok. Thanks a lot.
 
Top