PDO Update with variable table, column, row - php

I would like to build an ajax function that updates field variables in some tables.
The tables, fields, and rows are all variable and based on what is posted via the ajax function.
This is the code for my quickedit.php
define( "DB_DSN", "mysql:host=$host;dbname=$data" );
define( "DB_USERNAME", $user );
define( "DB_PASSWORD", $pass );
if(isset($_POST['table'])){ $table = $_POST['table'];}
if(isset($_POST['id'])){ $id = $_POST['id'];}
if(isset($_POST['field'])){ $field = $_POST['field'];}
if(isset($_POST['value'])){ $value = $_POST['value'];}
try {
$con = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
} catch (Exception $e) {
die("Connection Error");
}
try {
$st = $con->prepare("UPDATE :table SET :field = :value WHERE id = :id");
$st->execute(array(':table'=>$table, ':id'=>$id, ':field'=>$field, ':value'=>$value));
} catch (Exception $e) {
die("Query Error");
}
echo "table: ".$table." id: ".$id." field: ".$field." value: ".$value;
As you can see, I wish to dynamically select the table, column, and row.
I'm don't know a whole lot about exceptions, but none of them are being thrown
and it is successfully echoing the stuff at the bottom i told it to.

As you can see, I wish to dynamically select the table, column, and row.
Yes, we see it.
And this is where your idea is wrong.
This is quite contagious disease every good programmer have to outgrow. You are trying to make Universal Updater. Unfortunately, although the idea of some automation is usually all right, too much automation can be a disaster.
Your application have to have an idea what does it update and why. All the queries have to be pre-written and only data part may vary. It's all right to build a dynamical update from the several fields, but makeing even table name dynamical is too much.
As of your particular problem, ORM is what you really looking for. Look how it can be done with Yii Active record:
$post=$table::model()->findByPk($id);
$post->$field=$value;
$post->save(); // save the change to database

You'll need to build the original mysql sentence in the old way, using PHP to evaluate table and column names. Then use PDO to bind values to the fields.
$st = $con->prepare("UPDATE $table SET $field = :value WHERE id = :id");
$st->bindValue(':id',$id,PDO::PARAM_INT);
$st->bindValue(':value',$value,PDO::PARAM_STR);
$st->execute();
Be carefult not to allow quotes or semicolons in the variables youre evaluating. It's fairly easy to perform an SQL injection that way.

Related

android volly , get data from database row count [duplicate]

Im not trying to use a loop. I just one one value from one column from one row. I got what I want with the following code but there has to be an easier way using PDO.
try {
$conn = new PDO('mysql:host=localhost;dbname=advlou_test', 'advlou_wh', 'advlou_wh');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
$userid = 1;
$username = $conn->query("SELECT name FROM `login_users` WHERE username='$userid'");
$username2 = $username->fetch();
$username3 = $username2['name'];
echo $username3;
This just looks like too many lines to get one value from the database. :\
You can use fetchColumn():
$q= $conn->prepare("SELECT name FROM `login_users` WHERE username=?");
$q->execute([$userid]);
$username = $q->fetchColumn();
You could create a function for this and call that function each time you need a single value. For security reasons, avoid concatenating strings to form an SQL query. Instead, use prepared statements for the values and hardcode everything else in the SQL string. In order to get a certain column, just explicitly list it in your query. a fetchColumn() method also comes in handy for fetching a single value from the query
function getSingleValue($conn, $sql, $parameters)
{
$q = $conn->prepare($sql);
$q->execute($parameters);
return $q->fetchColumn();
}
Then you can simply do:
$name = getSingleValue($conn, "SELECT name FROM login_users WHERE id=?", [$userid]);
and it will get you the desired value.
So you need to create that function just once, but can reuse it for different queries.
This answer has been community edited addressing security concerns
Just like it's far too much work to have to get into your car, drive to the store, fight your way through the crowds, grab that jug of milk you need, then fight your way back home, just so you can have a milkshake.
All of those stages are necessary, and each subsequent step depends on the previous ones having been performed.
If you do this repeatedly, then by all means wrap a function around it so you can reuse it and reduce it down to a single getMyValue() call - but in the background all that code still must be present.

How to make foreign key updated automatically once the referenced key has been inserted with new value?

I have a 2 tables like this
I have put bmatricno as a referenced key for a foreign key called bmatricno_fk. Ok now i want to insert new data that contain bmatricno and bname for one table which is the first pic. And then i want the column for bmatricno_fk to be updated as well with the same value with the referenced key which is bmatricno. However i failed.
Then i try to insert manually with inserting on 2 tables. Then i have a problem with inserting multiple tables. I know about using transaction with commit because im using PDO. The problem is, since i have to use a code something like :bmatricno' => $_POST['bmatricno']. Therefore, i dont know how to use transaction that includes that kind of thing.
my code looks like this. (noob isnt it?)
$ses = $_SESSION['sBorrow'];
$query = "
INSERT INTO borrow (
bmatricno,
bname,
bdatetime
) VALUES (
:bmatricno,
:bname,
NOW()
)
;
INSERT INTO thesis(
bmatricno_fk
) VALUES (
:bmatricno
)
SELECT serialno, title
FROM thesis
WHERE serialno = :ses
";
$query_params = array(
':bmatricno' => $_POST['bmatricno'],
':bname' => $_POST['bname'],
':ses' => $_SESSION['sBorrow']
);
try
{
// Execute the query to create the user
$stmt = $db->prepare($query);
$result = $stmt->execute($query_params);
}
catch(PDOException $ex)
{
// Note: On a production website, you should not output $ex->getMessage().
// It may provide an attacker with helpful information about your code.
die("Failed to run query: " . $ex->getMessage());
}
That is my current code. So my question is does foreign key can be updated once referenced key got new value? If not, how to make transaction with the code i stated earlier?Please help me. I need to get this done.
NOTE: You notice that on second pic and column matricno_fk works well because i put an input to insert value, which means manually.
Well i did find the solution for my problems. frz3993 working but i just realized that one of my variables is an array. Therefore i use foreach on query. Since its an array, i'm not sure how to use foreach inside transaction since im in a rush. So i execute one by one query. and put foreach on my second statement like this.
$ses = $_SESSION['sBorrow'];
$query = "
INSERT INTO borrow (
bmatricno,
bname,
bdatetime
) VALUES (
:bmatricno,
:bname,
NOW()
)
";
$query_params = array(
':bmatricno' => $_POST['bmatricno'],
':bname' => $_POST['bname']
);
try
{
// Execute the query to create the user
$stmt = $db->prepare($query);
$result = $stmt->execute($query_params);
}
catch(PDOException $ex)
{
// Note: On a production website, you should not output $ex->getMessage().
// It may provide an attacker with helpful information about your code.
die("Failed to run query: " . $ex->getMessage());
}
//----------------------
$query = "
UPDATE thesis
SET
bmatricno_fk = :bmatricno,
bavailable = 'Unavailable'
WHERE
serialno = :ses
";
foreach($ses as $s){
$query_params = array(
':bmatricno' => $_POST['bmatricno'],
':ses' => $s
);
try
{
// Execute the query to create the user
$stmt = $db->prepare($query);
$result = $stmt->execute($query_params);
}
catch(PDOException $ex)
{
// Note: On a production website, you should not output $ex->getMessage().
// It may provide an attacker with helpful information about your code.
die("Failed to run query: " . $ex->getMessage());
}
}
//----------------------
I know this solution may not be best practical but well i need to complete it fast and i just have to present it on localhost anyway. Anyway, thanks for helping :)

sqlite create table from pdo resultset?

Does anyone have or can point to a good example of creating sqlite in-memory table using php pdo where the table columns formats are gathered directly from a PDO query result?
My use case is that I'd like to use SQLite3 to store multiple resultsets from a number of queries (all the same column order etc) that are returned from a number of different databases. The end goal is to use SQLite to "reduce" the data for finalization.
I understand I could write a custom function for each query result, but my goal is to implement a universal solution, not needing to know the table structure, passing x homogenous resultsets (PDO::FETCH_ASSOC array results for example) and return a temporary SQLite table name to be able to query the UNION of the resultset(s) with SQLite before discarding the data.
It seems like this would be out on the internet somewhere and the SQLite website even alludes to this being a use case, but all my searches point to basic SQLite howtos on creating and querying...thanks in advance!
Since nobody replied, here is a rough effort. This is based on the db handle being mySQL, but it may be possible to ignore types and let sqlite do some magic. If so, see this link:
https://www.sqlite.org/datatype3.html
try{
$link = connectToDB_PDO();
$strSQL="select * from website.customers";
$mySth=$link->prepare($strSQL);
$meta=array();
$mySth->execute();
foreach(range(0, $mySth->columnCount() - 1) as $column_index){
$meta[] = $mySth->getColumnMeta($column_index);
}
$result=$mySth->fetchAll(PDO::FETCH_ASSOC);
// Create new database in memory
$memdb = new PDO('sqlite::memory:');
$memdb->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Set errormode to exceptions
$tablename='mytable';
$colnames=array(); // for the insert statement below
$tableSQL="CREATE TABLE $tablename ( ";
foreach($meta as $col){
$colnames[]=$col['name'];
$tableSQL.=" ".$col['name']. " ".$col['native_type']." ";
if(array_key_exists('flags',$col)){
foreach($col['flags'] as $flag){
switch($flag)
{
case 'not_null':
$tableSQL.=" NOT NULL ";
break;
case 'primary_key':
$tableSQL.=" PRIMARY KEY ";
break;
default:
} // end switch
} // end each flag
} // end if flags
$tableSQL.=", ";
} // end each column
$tableSQL=rtrim($tableSQL,", ");
$tableSQL.=")";
$memdb->exec($tableSQL);
$pragmaSQL="PRAGMA table_info($tablename)";
$st2=$memdb->prepare($pragmaSQL);
$st2->execute();
$pragres=$st2->fetchAll(PDO::FETCH_ASSOC);
$insert = "INSERT INTO $tablename (".implode(",",$colnames).") ".
"VALUES (:".implode(",:",$colnames).")";
$stmt = $memdb->prepare($insert);
foreach ($result as $row) {
$parms=array();
for($i=0;$i<count($colnames);$i++){
$parms[':'.$colnames[$i]]=$row[$colnames[$i]]; // Bind parameters to statement variables
}
$stmt->execute($parms);
}
$strSQL="SELECT sum(customers_id) FROM $tablename";
$sth=$memdb->prepare($strSQL);
$sth->execute();
$result2=$sth->fetchAll(PDO::FETCH_ASSOC);
foreach ($result2 as $m) {
echo print_r($m,true);
}
$memdb->exec("DROP TABLE $tablename");
$memdb = null;
} catch(PDOException $e) {
echo $e->getMessage();
error_log($e->getMessage());
}
I'm not sure if this is the best answer, but its a start - anxious to see other's input!

return one value from database with mysql php pdo

Im not trying to use a loop. I just one one value from one column from one row. I got what I want with the following code but there has to be an easier way using PDO.
try {
$conn = new PDO('mysql:host=localhost;dbname=advlou_test', 'advlou_wh', 'advlou_wh');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
$userid = 1;
$username = $conn->query("SELECT name FROM `login_users` WHERE username='$userid'");
$username2 = $username->fetch();
$username3 = $username2['name'];
echo $username3;
This just looks like too many lines to get one value from the database. :\
You can use fetchColumn():
$q= $conn->prepare("SELECT name FROM `login_users` WHERE username=?");
$q->execute([$userid]);
$username = $q->fetchColumn();
You could create a function for this and call that function each time you need a single value. For security reasons, avoid concatenating strings to form an SQL query. Instead, use prepared statements for the values and hardcode everything else in the SQL string. In order to get a certain column, just explicitly list it in your query. a fetchColumn() method also comes in handy for fetching a single value from the query
function getSingleValue($conn, $sql, $parameters)
{
$q = $conn->prepare($sql);
$q->execute($parameters);
return $q->fetchColumn();
}
Then you can simply do:
$name = getSingleValue($conn, "SELECT name FROM login_users WHERE id=?", [$userid]);
and it will get you the desired value.
So you need to create that function just once, but can reuse it for different queries.
This answer has been community edited addressing security concerns
Just like it's far too much work to have to get into your car, drive to the store, fight your way through the crowds, grab that jug of milk you need, then fight your way back home, just so you can have a milkshake.
All of those stages are necessary, and each subsequent step depends on the previous ones having been performed.
If you do this repeatedly, then by all means wrap a function around it so you can reuse it and reduce it down to a single getMyValue() call - but in the background all that code still must be present.

MySQL query within foreach loop

I want to show all text messages from db where id=$e ($err is an array).
Inserted the query into the foreach loop, it works well but it does extra work (does query for every value of array).
Is there any other way to do it (i mean extract query from foreach loop)?
My code looks like this.
foreach ($err as $e)
{
$result = $db -> query("SELECT * from err_msgs WHERE id='$e'");
$row = $result -> fetch_array(MYSQLI_BOTH);
echo "<li><span>".$row[1]."</span></li>";
}
It is much more efficient to do this with implode() because it will only result in one database query.
if (!$result = $db->query("SELECT * FROM `err_msgs` WHERE `id`='".implode("' OR `id`='",$err)."'")) {
echo "Error during database query<br />\n";
// echo $db->error(); // Only uncomment this line in development environments. Don't show the error message to your users!
}
while ($row = $result->fetch_array(MYSQLI_BOTH)) {
echo "<li><span>".$row[1]."</span></li>\n";
}
Check the SQL IN clause.
Firstly, a bit of a lecture: embedding strings directly into your queries is going to cause you trouble at some point (SQL injection related trouble to be precise), try to avoid this if possible. Personally, I use the PDO PHP library which allows you to bind parameters instead of building up a string.
With regard to your question, I'm not sure I have understood. You say that it does extra work, do you mean that it returns the correct results but in an inefficient way? If so then this too can be addressed with PDO. Here's the idea.
Step 1: Prepare your statement, putting a placeholder where you currently have '$e'
Step 2: Loop through $err, in the body of the loop you will set the place holder to be the current value of $e
By doing this you not only address the SQL injection issue, you can potentially avoid the overhead of having to parse and optimise the query each time it is executed (although bear in mind that this may not be a significant overhead in your specific case).
Some actual code would look as follows:
// Assume that $dbdriver, $dbhost and $dbname have been initialised
// somewhere. For a mysql database, the value for $dbdriver should be
// "mysql".
$dsn = "$dbdriver:host=$dbhost;dbname=$dbname";
$dbh = new PDO($dsn, $dbuser, $dbpassword);
$qry = "SELECT * from err_msgs WHERE id = :e"
$sth = $dbh->prepare($qry);
foreach ($err as $e) {
$sth->bindParam(":e", $e);
$sth->execute();
$row = $sth->fetch();
// Prints out the *second* field of the record
// Note that $row is also an associative array so if we
// have a field called id, we could use $row["id"] to
// get its value
echo "<li><span>".$row[1]."</span></li>";
}
One final point, if you want to simply execute the query once, instead of executing it inside the loop, this is possible but again, may not yield any performance improvement. This could be achieved using the IN syntax. For example, if I'm interested in records with id in the set {5, 7, 21, 4, 76, 9}, I would do:
SELECT * from err_msgs WHERE id IN (5, 7, 21, 4, 76, 9)
I don't think there's a clean way to bind a list using PDO so you would use the loop to build up the string and then execute the query after the loop. Note that a query formulated in this way is unlikely to give you any noticable performance improvment but it really does depend on your specific circumstances and you'll just have to try it out.
You can do this much simpler by doing
$err_csv = implode("','",$err);
$sql = "SELECT FROM err_msgs WHERE id IN ('$err_csv')";
$result = $db -> query($sql);
while ($row = $result -> fetch_array(MYSQLI_BOTH))
{
echo "<li><span>".$row[1]."</span></li>";
}
That way you don't have to keep sending queries to the database.
Links:
http://php.net/manual/en/function.implode.php

Categories