I'm sending some data through to a mysql server via android in an attempt to update some details. Currently the php side looks something like
this:
for($i=0; $i<(10); $i++){
for($k=0; $k<(10); $k++){
mysql_query("UPDATE sometable SET data_".$i."_".$k." = '10'
WHERE id = '".$_REQUEST['id']."'");
}
}
I have to use a loop becuase I'll be building up lots of generic types of data with the style "data_x". Unfortunately, this layout doesn't
seem to update any fields in the database.
Does this method create some type of space, or just simply disrupt a complete variable when read in a statement?
Thanks
Ok, couple of things about current iteration.
Log/output your errors!
`$res = mysql_query( $query ); if( !$res ) log( myslq_error() );/* or die or whatever */`
Do one update, not 100.
$query = "UPDATE sometable SET";
for($i=0; $i<(10); $i++){
for($k=0; $k<(10); $k++){
$query .= ' data_'.$i.'_'.$k.' = \'10\''
if( !( $k == $i && $i == 10 ) ) $query .= ',';
}
}
//see side note below
$query .= 'WHERE id = ' . mysql_real_escape_string( $_REQUEST['id'] );
$res = mysql_query( $query );
if( !$res ) do_something_with_error( mysql_error() );
100 updates can make your database/PHP angry and the last thing you want is an angry database. Further, this only does one array lookup in REQUEST, whereas the code above does 100. (O(1) * 100 is still 100).
As a side note: just because something is supposed to be sent from Android, that is no reason to expect that it does not need to be properly escaped. Remember the lessons of Bobby Tables!
I also cannot suggest strongly enough that you reconsider your schema. That may seem to be the easiest way to handle things right now, but later developers (including yourself) will wonder what the heck was supposed to be stored there. I've worked on projects like that and they were not fun. (On the other hand, I don't know your specifics, so I could be completely wrong).
This was addressing an initial copy paste error:
At a bare minimum, PHP can't parse this line:
for(ik=0; $i<(10); $i++)
Rewrite it with the dollar sign:
for($i=0; $i<(10); $i++)
Did you debug the code at all?
Is the query actually valid and does the generated field 'data_X_X' definitely exist in the table 'sometable'?
My guess is that the generated field name does not exist in your table.
Related
I have a bunch of photos on a page and using jQuery UI's Sortable plugin, to allow for them to be reordered.
When my sortable function fires, it writes a new order sequence:
1030:0,1031:1,1032:2,1040:3,1033:4
Each item of the comma delimited string, consists of the photo ID and the order position, separated by a colon. When the user has completely finished their reordering, I'm posting this order sequence to a PHP page via AJAX, to store the changes in the database. Here's where I get into trouble.
I have no problem getting my script to work, but I'm pretty sure it's the incorrect way to achieve what I want, and will suffer hugely in performance and resources - I'm hoping somebody could advise me as to what would be the best approach.
This is my PHP script that deals with the sequence:
if ($sorted_order) {
$exploded_order = explode(',',$sorted_order);
foreach ($exploded_order as $order_part) {
$exploded_part = explode(':',$order_part);
$part_count = 0;
foreach ($exploded_part as $part) {
$part_count++;
if ($part_count == 1) {
$photo_id = $part;
} elseif ($part_count == 2) {
$order = $part;
}
$SQL = "UPDATE article_photos ";
$SQL .= "SET order_pos = :order_pos ";
$SQL .= "WHERE photo_id = :photo_id;";
... rest of PDO stuff ...
}
}
}
My concerns arise from the nested foreach functions and also running so many database updates. If a given sequence contained 150 items, would this script cry for help? If it will, how could I improve it?
** This is for an admin page, so it won't be heavily abused **
you can use one update, with some cleaver code like so:
create the array $data['order'] in the loop then:
$q = "UPDATE article_photos SET order_pos = (CASE photo_id ";
foreach($data['order'] as $sort => $id){
$q .= " WHEN {$id} THEN {$sort}";
}
$q .= " END ) WHERE photo_id IN (".implode(",",$data['order']).")";
a little clearer perhaps
UPDATE article_photos SET order_pos = (CASE photo_id
WHEN id = 1 THEN 999
WHEN id = 2 THEN 1000
WHEN id = 3 THEN 1001
END)
WHERE photo_id IN (1,2,3)
i use this approach for exactly what your doing, updating sort orders
No need for the second foreach: you know it's going to be two parts if your data passes validation (I'm assuming you validated this. If not: you should =) so just do:
if (count($exploded_part) == 2) {
$id = $exploded_part[0];
$seq = $exploded_part[1];
/* rest of code */
} else {
/* error - data does not conform despite validation */
}
As for update hammering: do your DB updates in a transaction. Your db will queue the ops, but not commit them to the main DB until you commit the transaction, at which point it'll happily do the update "for real" at lightning speed.
I suggest making your script even simplier and changing names of the variables, so the code would be way more readable.
$parts = explode(',',$sorted_order);
foreach ($parts as $part) {
list($id, $position) = explode(':',$order_part);
//Now you can work with $id and $position ;
}
More info about list: http://php.net/manual/en/function.list.php
Also, about performance and your data structure:
The way you store your data is not perfect. But that way you will not suffer any performance issues, that way you need to send less data, less overhead overall.
However the drawback of your data structure is that most probably you will be unable to establish relationships between tables and make joins or alter table structure in a correct way.
I populate a web form with rows of data. Some of the fields I need to be updatable so I put the value into a text field. MySQL query is:
SELECT * FROM results WHERE EventID = %s AND CompNo = %s", GetSQLValueString($colname_rsResults, "int"),GetSQLValueString($colname2_rsResults, "int"));
EventID and CompNo are passed in the URL.
Let's say the result is 50 rows. I want to be able to update the Name field (eg, make correction to the spelling), click a button and have the code update the database with any new values. It doesn't matter that most of the values will not change as this is a very infrequent operation.
I used to be able to do this in ASP but I can't seem to do in PHP.
This is the code I am using and I think it is completely wrong!!
if ((isset($_POST["JM_update"])) && ($_POST["JM_update"] == "form1")) {
$i = 0;
$j = $totalRows_rsResults;
while($i < $j)
$resultID=$_GET['ResultID'];
$vDelete=$_GET['Del'];
if ($vDelete == 1) {
$delSQL = sprintf("DELETE FROM Results WHERE ResultID=$resultID");
mysql_query($delSQL,$connFeisResults);
} else {
$name=$_GET['Name'];
$qual=$_GET['Qual'];
$updateSQL = sprintf("UPDATE results SET Name = ".$name{$i}.", Qual = ".$qual[$i]." WHERE ResultID=$resultID");
mysql_query($updateSQL, $connFeisResults);
$i++;
}
}
There is also a checkbox at the end of each row to check if I need that record deleted. That doesn't work either!!
I am using Dreamweaver CS6 and trying to adapt the update behaviours etc.
Any thoughts? Many thanks in advance.
It looks like you're missing an opening brace after your while statement.
--UPDATED
Also, check your sprintf statements -- they look wrong, and they look like they're writing the raw '$resultID' to the SQL String, instead of the value within it.
See how to do it here: http://www.talkphp.com/general/1062-securing-your-mysql-queries-sprintf.html
I'm really new to PHP but I've been learning all I can, but I'm also aware that I have a lot to learn so go easy on me.
I'm currently working on a classifieds script and although the code is severely dated, It was a lot worse before I began cleaning it up and now I'm just trying to get the classifieds stable again, then I plan on going back and updating things to a more modern language (PDO) but for now I have NO IDEA on where to begin (and don't want to be reading for months while getting nowhere as I have been while learning HTML, CSS, PHP and JS)
The code below originally displayed the Title column from the table it was fetching the data from (tt_%s) but I have since modified the form which inserts the data into the DB so now there is no longer a "Title" column and in it's place there is now Year and Model from one table and Manufacturer from another table but this is where I get confused and am asking for help.
Presently this is what I am looking at; (Below the code I'll explain more)
<?php
echo "<div class='mostPopular'>";
echo "Popular<br>Listings";
$node = new sqlNode();
$node->table = "types";
$node->select = "ID";
$node->orderby = "ORDER BY rand()";
if(($typeRS = $mysql->select($node)) === false )
die('Unable to Retrieve Ad Type');
$sql = array();
$typeID = 0;
while( $adType = mysql_fetch_assoc($typeRS) ){
$typeID = sprintf("`tt_%s`", abs(intval($adType['ID'])));
$sql[] = sprintf("SELECT %s.Year, %s.Hits, %s.CategoryID, %s.ID, CONCAT('','%s') AS TypeID FROM %s WHERE (`ExpireDate` > NOW()) ",
$typeID,
$typeID,
$typeID,
$typeID,
intval($adType['ID']),
$typeID);
}
$sqlStr = #implode("union ",$sql);
$sqlStr .= " ORDER BY Hits DESC LIMIT 5";
if(($adRS = $mysql->exSql($sqlStr)) === false)
die('Unable to Retrieve Most Popular Ads');
while( $ad = mysql_fetch_assoc($adRS) ){
echo "<p>";
echo "<a href='detail.php?fatherID=".$ad['CategoryID']."&TypeID=".$ad['TypeID']."&ListingID=".$ad['ID']."'>";
echo $ad['Title'];
echo "</a>";
echo "</p>";
}
echo "</div>";
?>
For starters, I don't know what CONCAT('','%s') is all about, nor do I know what $sqlStr = #implode("union ",$sql); is all about.
In addition to these issues, considering that this code is outdated and I should be switching to PDO, I was hoping someone could show me exactly how to perform these queries with PDO as then I could learn by example and apply the same procedures to other queries throughout the site.
If anyone wouldn't mind conversing with me to the point where I can perform the same outcome with PDO I'd be most appreciative and I thank you all in advance while I eagerly await your replies.
BTW, I ask this after studying every PHP and MySql tutorial I can find for the past several months
Thanks
Although "Please rewrite this code to PDO" being too localized one, the real problem you have require different solution.
First of all, you need to fix your database architecture. It's terrible.
Premature optimization, being the root of all evil, depraved you from the right ways. There is no point in splitting your data into small chunks if you going to union them anyway.
You have to have one table for the ads.
It will make all this code obsolete, leaving only one regular query which can be run in one conventional PDO call.
Next, this code has been written by some sprintf() maniac, who made it overcomplicated out of nowhere. As a matter of fact, not a single sprintf() is really needed here.
$sql = array();
while( $row = mysql_fetch_assoc($typeRS) ){
$typeID = abs($row['ID']);
$sql[] = "SELECT Year, Hits, CategoryID, ID, '$typeID' AS TypeID
FROM tt_$typeID WHERE ExpireDate > NOW()";
}
$sqlStr = implode("union ",$sql)." ORDER BY Hits DESC LIMIT 5"
is enough.
But again, no need for this union query. Everything have to be performed via single ordinary query like this one
SELECT Year, Hits, CategoryID, ID, TypeID FROM ads ORDER BY Hits DESC LIMIT 5
which you no doubt will be able to run using whatever PDO example you have
I've got a weird little problem.
I'm writing a script that inserts multiple rows into a MySQL DB, quirk is that their IDs are not necessarily a nice neat 1,2,3 set as they're being edited. The continue statement must be skipping every row as it times out in PHP. This has been doing my head in for the past few hours. Any ideas?
Thanks!
$items = $_POST['invItemQuantity'];
$i = 1;
while($i <= $items) {
if(!isset($_POST['item'.$i])) continue;
//assign posts to variables
$date = $_POST["item_date".$i];
$description = $_POST["description".$i];
$price = $_POST["price".$i];
$ID = $_POST["item".$i];
$que = "UPDATE invoice_items SET date='".$date."', description ='".$description."', price ='".$price."' WHERE item_ID=".$ID;
$test .= $que."<br>";
$i++;
}
if(!isset($_POST['item'.$i])) continue;
You forgot to increment i in that case. Fix it to :
if(!isset($_POST['item'.$i])) { $i++; continue; }
Since you need to iterate over all the item fields no matter what, a for loop might make it easier to not forget your increment action.
$items = $_POST['invItemQuantity'];
for($i=1; $i<=$items; $i++)
{
if(!isset($_POST['item'.$i])) continue;
// ...
}
You might also want to perform some validation on "$_POST['invItemQuantity']" before you use it in your code (e.g. verify it contains a number of expected range).
Your whole approach to this is very strange. I'm guessing in your form you have item1, item2, item3 etc. Instead you should have items[] for all of them to submit it as an array. Do the same for each item_date, description and price. Then simply run:
foreach($_POST['items'] as $i => $item) {
if(!empty($item)) {
$date = mysql_real_escape_string(trim($_POST['item_date'][$i]));
$description = mysql_real_escape_string(trim($_POST['description'][$i]));
$price = mysql_real_escape_string(trim($_POST['price'][$i]));
$ID = (int)$_POST['item'][$i];
//UPDATE QUERY...
}
}
The other thing is you should never take user input and directly input it into the database as that leaves you wide open to SQL injections. You should always escape it first using mysql_real_escape_string (for mysql). Even better would be to learn MySQLi or PDO.
You may also wish to look at filter_input, a good way to make sure that your inputs are clean. You should never trust user input and should always test it against a white list of suitable variables if possible.
I have a submission script that I wrote in PHP. It is used by multiple surveys at our organization. The surveys are created by other users. When they submit to the script, PHP puts the data into the appropriate table in MySQL. The error that I run into sometimes is that the user(s) update the form. They add a field, or rename an input and the script doesn't account for it since it expects everything to be the same. So, I am trying to find a way to make it accomodate for when a new field is added. Here is what I have:
if( mysql_num_rows( mysql_query("SHOW TABLES LIKE '".$survey."'"))){
echo "table exists";
$sql = "SELECT * FROM " . $survey . ";";
$result = mysql_query($sql)
or die(mysql_error());
$i=0;
while($row = mysql_fetch_row($result));{
echo $row[0];
foreach($_POST as $k => $v){
$i++;
if($k != $row[$i]){
$query = "ALTER TABLE " . $survey . " ADD " . $k . " VARCHAR(100);";
mysql_query($query)
or die(mysql_error());
}
}
}
}
I am used to doing while loops in JS, so I don't know if using i works here (actually, I know it doesn't work... because it doesn't work...). What I am trying to say is that if a key doesn't match a current field name, then add it to the table. How can I return $row correctly?
When I submit to the script it says:
Duplicate column name 'V4'
I have echo $row[0] but it returns a 1. Which is the is the int used in the primary key for the for the first record.
You have a ; at the end of your while loop declaration that shouldn't be there. Not sure if that is causing the problem as you don't say what the above code does do. Update the question if the ; is not the issue.
Your while loop declaration should look like this: while($row = mysql_fetch_row($result)) {
Also, as Marc B so diplomatically put it in a comment to your question, you should be escaping any user input that goes directly into a query.
The easiest way to do this is to use $survey = mysql_real_escape_string($survey), before your first use of $survey, as a start or switch to PDO/MySQLi and use input binding (prepared statements). Here are the prepared statements docs for PDO. More can, and should, be done to protect yourself, but the above is a good start.