$wpdb not working, even though validation comes back positive - php

I wonder if anybody can help me. I'm trying add some data to a table within a wordpress database. I'm using the $wpdb class and every time I run the code, the validation I got in place comes back positive. But when I check the table in the database, it's empty.
My Code:
// Define global $wpdb
global $wpdb;
// Retrieve information from the form
$location = $_POST['txtLocation'];
$price = $_POST['txtPrice'];
$type = $_POST['sltType'];
$revenue = $_POST['txtRevenue'];
$surgeries = $_POST['txtSurgeries'];
$tenure = $_POST['sltTenure'];
$upload = $_POST['txtUpload'];
// SQL statement to insert information from the form into the database
$sql = $wpdb->prepare("INSERT INTO practices ('Location', 'Price', 'Type', 'Revenue', 'No. of Surgeries', 'Tenure', 'PDF') VALUES (%s,%s,%s,%s,%s,%s,%s", $location, $price, $type, $revenue, $surgeries, $tenure, $upload);
$result = $wpdb->query($sql);
if (!result) {
echo '<p class="sql-error">There was a problem uploading the practice to the database</p>';
} else {
echo '<p class="sql-success">The practice was uploaded to the database</p>';
}
echo $wpdb->last_query;
Does anybody know why my code is doing this???
Thanks

Forgot a closing ) in your query.
Here
VALUES (%s,%s,%s,%s,%s,%s,%s
^
Try:
$sql = $wpdb->prepare("INSERT INTO practices ('Location', 'Price', 'Type', 'Revenue', 'No. of Surgeries', 'Tenure', 'PDF') VALUES (%s,%s,%s,%s,%s,%s,%s)", $location, $price, $type, $revenue, $surgeries, $tenure, $upload);
Also it is
if (!$result) {
^

In addition to closing the VALUES statement in your query as has been suggested, you might find that referencing the column names using ' would also give you issues.
MySQL expects column identifiers to be enclosed using backticks: `.

Related

SQL INSERT function with PHP only

edit I changed the code to the suggestion answer, all snippets now updated
currently I am playing around with PHP. Therefore I am trying to build a programm which can execute SQL commands. so, what I am trying is to write some functions which will execute the query. But I came to a point where I coundn't help myself out. My trouble is, for the INSERT INTO command, I want to give an array, containing the Data that shall be inserted but I simply can't figure out how to do this.
Here is what I got and what I think is relevant for this operation
First, the function I want to create
public function actionInsert($data_values = array())
{
$db = $this->openDB();
if ($db) {
$fields = '';
$fields_value = '';
foreach ($data_values as $columnName => $columnValue) {
if ($fields != '') {
$fields .= ',';
$fields_value .= ',';
}
$fields .= $columnName;
$fields_value .= $columnValue;
}
$sqlInsert = 'INSERT INTO ' . $this->tabelle . ' (' . $fields . ') VALUES (' . $fields_value . ')';
$result = $db->query($sqlInsert);
echo $sqlInsert;
if ($result) {
echo "success";
} else {
echo "failed";
}
}
}
and this is how I fil the values
<?php
require_once 'funktionen.php';
$adresse = new \DB\Adressen();
$adresse->actionInsert(array('nachname'=>'hallo', 'vorname'=>'du'));
My result
INSERT INTO adressen (nachname,vorname) VALUES (hallo,du)failed
What I wish to see
success
and of course the freshly insertet values in the database
There are a few things to consider when you are working with relational databases without using PDO:
What is the database that you are using.
It's your decision to choose from MySQL, postgreSQL, SQLite and etc., but different DBs generally have different syntax for inserting and selecting data, as well as other operations. Also, you may need different classes and functions to interact with them.
That being said, did you checkout the official manual of PHP? For example, An overview of a PHP application that needs to interact with a MySQL database.
What is the GOAL you are trying to accomplish?
It's helpful to construct your SQL first before you are messing around with actual codes. Check if your SQL syntax is correct. If you can run your SQL in your database, then you can try to implement your code next.
What's the right way to form an SQL query in your code?
It's okay to mess around in your local development environment, but you should definitely learn how to use prepared statements to prevent possible SQL injection attacks.
Also learn more about arrays in PHP: Arrays in PHP. You can use key-value pairs in a foreach loop:
foreach ($keyed_array as $key => $value) {
//use your key and value here
}
You don't need to construct your query in the loop itself. You are only using the loop to construct the query fields string and VALUES string. Be very careful when you are constructing the VALUES list because your fields can have different types, and you should add double quotes around string field values. And YES, you will go through all these troubles when you are doing things "manually". If you are using query parameters or PDO or any other advanced driver, it could be much easier.
After that, you can just concatenate the values to form your SQL query.
Once you get more familiar with the language itself and the database you are playing with, you'll definitely feel more comfortable. Good luck!
Is this inside of a class? I assume the tabelle property is set correctly.
That said, you should correct the foreach loop, that's not used correctly:
public function actionInsert($data_values) //$data_values should be an array
{
$db = $this->openDB();
if ($db) {
foreach ($data_values as $data){
// $data_values could be a bidimensional array, like
// [
// [field1=> value1, field2 => value2, field3 => value3],
// [field1=> value4, field2 => value5, field3 => value6],
// [field1=> value7, field2 => value8, field3 => value9],
// ]
$fields = Array();
$values = Array();
foreach($data as $key => $value){
array_push($fields,$key);
array_push($values,"'$value'");
}
$sqlInsert = 'INSERT INTO ' . $this->tabelle . ' (' . join(',',$fields) . ') VALUES (' . join(',',$values) . ')';
$result = $db->query($sqlInsert);
echo $sqlInsert;
if ($result) {
echo "success";
} else {
echo "failed";
}
}
}
This is a rather basic approach, in which you cycle through you data and do a query for every row, but it isn't very performant if you have big datasets.
Another approach would be to do everything at once, by mounting the query in the loop and sending it later (note that the starting array is different):
public function actionInsert($data_values) //$data_values should be an array
{
$db = $this->openDB();
if ($db) {
$vals = Array();
foreach ($data_values['values'] as $data){
// $data_values could be an associative array, like
// [
// fields => ['field1','field2','field3'],
// values => [
// [value1,value2,value3],
// [value4,value5,value6],
// [value7,value8,value9]
// ]
// ]
array_push('('.join(',',"'$data'").')',$vals);
}
$sqlInsert = 'INSERT INTO ' . $this->tabelle . ' (' . join(',',$data_values['fields']) . ') VALUES '.join(' , ',$vals);
$result = $db->query($sqlInsert);
echo $sqlInsert;
if ($result) {
echo "success";
} else {
echo "failed";
}
}
By the way dragonthought is right, you should do some kind of sanitizing for good practice even if you don't make it public.
Thanks to #Eagle L's answer, I figured a way that finally works. It is diffrent from what I tryed first, but if anyone having similar troubles, I hope this helps him out.
//get the Values you need to insert as required parameters
public function actionInsert($nachname, $vorname, $plz, $wohnort, $strasse)
{
//database connection
$db = $this->openDB();
if ($db) {
//use a prepared statement
$insert = $db->prepare("INSERT INTO adressen (nachname, vorname, plz, wohnort, strasse) VALUES(?,?,?,?,?)");
//fill the Values
$insert->bind_param('ssiss', $nachname, $vorname, $plz, $wohnort, $strasse);
//but only if every Value is defined to avoid NULL fields in the Database
if ($vorname && $nachname && $plz && $wohnort && $strasse) {
edited
$inserted = $insert->execute(); //added $inserted
//this is still clumsy and user unfriendly but serves my needs
if ($inserted) {//changed $insert->execute() to $inserted
echo 'success';
} else {
echo 'failed' . $inserted->error;
}
}
}
}
and the Function call
<?php
require_once 'funktionen.php';
$adresse = new \DB\Adressen();
$adresse->actionInsert('valueWillBe$nachname', 'valueWillBe$vorname', 'valueWillBe$plz', 'valueWillBe$wohnort', '$valueWillBe$strasse');

Real_escape_string prevents INSERT statement from working MYSQL PHP

So I'm making my own blog scripts using MYSQL and PHP.
I had the whole 'writing the blog to a database' thing working perfectly, until I realised that if you tried to write a blog with speech marks, this would prevent the INSERT statement from working (obviously - the speechmarks were ending the SQL statement).
So I tried to use real_escape_string, and now the INSERT doesn't work even if you exclude quotes.
I tried using:
sqlstate
in order to find out the issue, and it returned "42000" - which, after googling for a little bit, refers to a syntax error, which doesn't make much sense as there is no syntax error before the use of real_escape_string.
Also, I'm now getting this error:
Call to a member function close() on a non-object in /postarticle.php on line 37
Which refers to the close() call in the ELSE statement.
Please may you help? Been going round in circles for a while. Here is my code:
<?php
$host = 'CENSORED';
$user = 'CENSORED';
$pass = 'CENSORED';
$db = 'CENSORED';
$connection = new mysqli($host,$user,$pass,$db);
$_SESSION["article"] = $_POST["article"];
$date_of_blog = getdate();
$article = ($_SESSION["article"]);
$sql1 = "SELECT * FROM `Blogs`";
$res1 = $connection->query($sql1);
$newrows = $res1->num_rows + 1;
$sql2 = "INSERT INTO Blogs(BlogID, Blog_Contents, D_O_B) VALUES ('$newrows','$article','$date_of_blog')";
$sql2 = $connection->real_escape_string($sql2);
$res2 = $connection->query($sql2);
if ($res2->num_rows == $newrows)
{
$res->close();
$connection->close();
header( 'Location: adminpanel.php' );
}
else
{
echo ($connection->sqlstate);
$connection->close();
$res->close();
}
exit();
?>
Also, on a side note, the getdate() call that I've got has never worked. In the database every blog post comes up as:
0000:00:00 00:00:00
EDIT:
Issue is now solved. Find the functional code below:
<?php
$host = 'CENSORED';
$user = 'CENSORED';
$pass = 'CENSORED';
$db = 'CENSORED';
$connection = new mysqli($host,$user,$pass,$db);
$_SESSION["article"] = $_POST["article"];
$article = ($_SESSION["article"]);
$article = $connection->real_escape_string($article);
$sql1 = "SELECT * FROM `Blogs`";
$res1 = $connection->query($sql1);
$newrows = $res1->num_rows + 1;
$sql2 = "INSERT INTO Blogs(BlogID, Blog_Contents, D_O_B) VALUES (\"$newrows\",\"$article\",CURDATE())";
$res2 = $connection->query($sql2);
if ($res2 != false)
{
header( 'Location: adminpanel.php' );
}
else
{
echo ($connection->sqlstate);
}
$connection->close();
$res->close();
exit();
?>
I'm very sorry if these questions are basic and annoy the professionals around here; I've tried to follow the guidelines and I've googled for a while etc. I just haven't found any solutions that match my issue(s).
Thankyou for your time.
There are a number issues with the code as originally posted. Chiefly, the cause of the two issues you initially identified is a misuse of mysqli::real_escape_string(). It needs to be called on each variable individually which appears in the code. So instead of calling it on the whole statement, it must be called multiple times for multiple variables like:
$article = $connection->real_escape_string($connection);
The failure of the query due to incorrect quoting (due to real_escape_string()) is the reason for the error message calling close().
As ascertained in the comments, you are using num_rows + 1 to validate that one new row has been inserted based on the previous number of rows returned. This is problematic for a few reasons. Mainly, it exposes a race condition wherein a row may be inserted from two sessions at once and one or both will fail because the expected value for $newrows doesn't match. Really BlogID should be an auto_increment column in your database. That eliminates the need for any logic around it whatsoever. You don't even need to include it in the INSERT because it will be automatically incremented.
That also completely eliminates the need for the first SELECT statement.
Substituting MySQL's native NOW() function for the date value, you can simplify the statement to:
INSERT INTO Blogs (Blog_Contents, D_O_B) VALUES ('$article', NOW())
To test success or failure of the insert, you just need to verify that its variable is not false.
Putting this together, your code can be reduced as:
if (!isset($_POST['article'])) {
// exit or handle an empty post somehow...
}
$connection = new mysqli($host,$user,$pass,$db);
$_SESSION["article"] = $_POST["article"];
// Escape $article for later use
$article = $connection->real_escape_string($_SESSION["article"]);
// Only an INSERT is needed. $article is already escaped
$sql = "INSERT INTO Blogs (Blog_Contents, D_O_B) VALUES ('$article', NOW())";
// Run the query
$res = $connection->query($sql);
// Test for failure by checking for a false value
if ($res) {
// The connection & resource closure can be omitted
// PHP will handle that automatically and implicitly.
header( 'Location: adminpanel.php' );
// Explictly exit as good practice after redirection
exit();
}
else {
// The INSERT failed. Check the error message
echo $connection->error;
}
This should bring your current code into working order. However, since you're learning this it is an excellent time to begin learning to use prepared statements via prepare()/bind_param()/execute() in MySQLi. This is a recommended best practice to prevent SQL injection, although using real_escape_string() works as long as you use it correctly and never forget.
See How can I prevent SQL injection in PHP for examples.
But it would look like:
// connection already established, etc...
// Prepare the statement using a ? placeholder for article
$stmt = $connection->prepare("INSERT INTO Blogs (Blog_Contents, D_O_B) VALUES (?, NOW())");
if ($stmt) {
// bind in the variable and execute
// Note that real_escape_string() is not needed when using
// the ? placeholder for article
$stmt->bind_param('s', $_SESSION['article']);
$stmt->execute();
// Redirect
header( 'Location: adminpanel.php' );
exit();
}
else {
echo $connection->error;
}
You need to apply the real_escape_string function to the variables not the entire SQL string.
$sql2 = "INSERT INTO Blogs(BlogID, Blog_Contents, D_O_B) VALUES ('".$connection->real_escape_string($newrows)."','".$connection->real_escape_string($article)."','".$connection->real_escape_string($date_of_blog)."')";
The purpose is to remove anything that might be misinterpreted as query functions by MySQL, but there are parts of the query that you obviously want to be interpreted as such.

How to insert data into MySql using an associative array [duplicate]

This question already has an answer here:
Mysqli prepared statements build INSERT query dynamically from array
(1 answer)
Closed 8 months ago.
I am now having a problem inserting data in associative array with its key as fields in the table and the values to be inserted into MySql database. Here is my code.
<?php
$table = 'articles';
$data = array(
'title' => 'Header',
'content' => 'This is content',
'author' => 'James');
$keys = implode(', ', array_keys($data));
$values = implode(', ', array_values($data));
$sql = 'insert into '.$table.'('.$keys.') values ('.$values.')';
$db = new mysqli('localhost', 'root', 'root', 'blog');
$db->query($sql);
?>
With this code, I wasn't able to insert the data into the database so I try to echo the query string out and I got something like this :
insert into articles(title, content, author) values (Header, This is content, James)
However, if I use the single quote in each value like this
insert into articles(title, content, author) values ('Header', 'This is content', 'James')
I can successfully insert the data into the database.
So I don't know what's wrong here. Is it a problem with the quote sign or not because when I use the single quote, this seems to work.
So please help me find the proper solution for this...
For the query you need to enclose each value in quotes. To do that you can change your implode statement to include the quotes to around the values -
$values = "'" .implode("','", array_values($data)) . "'";
EXAMPLE-demo
You should also be checking for errors.
Replace $db->query($sql);
with
if(!$result = $db->query($sql)){
die('There was an error running the query [' . $db->error . ']');
}
else{
echo "Data inserted.";
}
So I don't know what's wrong here. Is it a problem with the quote sign or not because when I use the single quote, this seems to work.
Yes, you need to use the single quote.
You can check it out:
$values = implode(', ', array_values($data));
Into something like it:
$values = implode (',', array_map (
function ($z)
{
return ((is_numeric ($z) || (is_string ($z) ? ($z == "NOW()" ? true : false) : false) || (is_array ($z)?(($z=implode(";",$z))?false:false):false)) ? $z : "'" . utf8_decode ($z) . "'");
}, array_values ($data)));
The idea is that you make every value field quoted, I meant value field by value field in the query. For instance, in my example, the function ignores NOW() as string, and keep it up to work as SQL's timestamp. Because if you treat it as string type, the command wouldn't work properly.
Anyway, the above is ugly and insecure.
I would advice you to look for some ORM like RedBeanORM or, maybe, use the proper PHP MySQL version like MySQLi. Mainly to avoid SQL injections.
Look one ORM example:
require 'rb.php';
R::setup();
$post = R::dispense('post');
$post->text = 'Hello World';
$id = R::store($post); //Create or Update
$post = R::load('post',$id); //Retrieve
R::trash($post); //Delete
Look one PHP MySQL improved version example:
$stmt = mysqli_prepare($link, "INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
mysqli_stmt_bind_param($stmt, 'sssd', $code, $language, $official, $percent);
$code = 'DEU';
$language = 'Bavarian';
$official = "F";
$percent = 11.2;
mysqli_stmt_execute($stmt);
Good luck. Good learning.
Positional place-holders:
$values = implode(', ',
array_fill(0, count($data), '?')
);
// insert into articles(title, content, author) values (?, ?, ?)
Named place-holders:
$values = implode(', ', array_map(
function($value){
return ":$value";
},
array_keys($data)
));
// insert into articles(title, content, author) values (:title, :content, :author)
Not necessarily the nicest or best code.
As about the parameter array itself, I'm not familiar with mysqli but with many DB extensions you could use $data as-is.

Do $wpdb->insert(..) and $wpdb->update(..) automatically sanitize data?

I'm trying to ensure that I avoid any SQL injections so I'm curious how WordPress handles these types of situations.
I would like to use the WordPress wrapper to insert new values into the database. Say I have the following snippet:
<?PHP
$var = $_POST['var'];
$qry = $wpdb->insert(
'my_table',
array(
'var' => $var,
'column2' => 123
)
);
if ($qry) {
$new_record = $wpdb->insert_id;
echo 'Record was inserted successfully with an id of ' . $new_record_id;
} else {
echo "There was an error with the SQL query";
}
?>
I looked into the WordPress Codex and it says not to escape these values but I want to ensure that I'm not leaving myself open to SQL injections. Am I protected or is there anything else I need to do? Do I have to worry about Select statements as well?
Here is the Codex for reference: http://codex.wordpress.org/Class_Reference/wpdb
Thanks in advance!
You are safe, the WPDB will sanitize the data for you.

Delete row not working in joomla

I'm creating a component in joomla and I'm having some problems using the database, specifically to delete rows. The code below is what I'm using
$db = JFactory::getDbo();
$query = $db->getQuery(true);
// delete if this date already exists for this user
$conditions = array(
$db->quoteName('userid') . '='.$array['userid'],
$db->quoteName('date') . '='.$date
);
$query->delete($db->quoteName('#__timereport_schedule'));
$query->where($conditions);
$db->setQuery($query);
$result = $db->execute();
So what I'm trying to do here is delete the rows that match the given userid and date, fairly simple. However it ends up not affecting the database. I know the variables $array['userid'] and $date are correct because the same are used later in the same function to do a insert (it's supposed to delete the record if it exists and make a new one) and the insert works fine which means I end up with duplicate entries.
example row that was succesfully inserted:
(userid, date, starttime, endtime, id, enddate, leave, days)
VALUES
(456, '2013-01-01', '08:00:00', '16:00:00', 448, '2013-01-01', '3', '["Tue"]')
with:
$query = $db->getQuery(true);
$columns = array('userid', 'date', 'starttime', 'endtime', 'id', 'leave');
$values = array("'".$array['userid']."'", "'".$date."'", "'".$array['starttime']."'", "'".$array['endtime']."'", "'null'", "'".$array['leave']."'");
$query
->insert($db->quoteName('#__timereport_schedule'))
->columns($db->quoteName($columns))
->values(implode(',', $values));
$db->setQuery($query);
try {
$result = $db->execute();
} catch (Exception $e) {
return $e;
}
What am I missing? I followed the http://docs.joomla.org/Inserting,_Updating_and_Removing_data_using_JDatabase#Deleting_a_Record example to create this query.
The below code should work since I've defined sample date and userid. Also, and most importantly, you should be quoting the data (much more important than the db fields, btw):
$array['userid'] = 127;
$date = date("Y-m-d H:i:s");
$db = JFactory::getDbo();
$query = $db->getQuery(true);
// delete if this date already exists for this userv
$conditions = array(
$db->quoteName('userid') . '='.$db->quote($array['userid']),
$db->quoteName('date') . '='.$db->quote($date)
);
$query->delete($db->quoteName('#__timereport_schedule'));
$query->where($conditions);
try {
$db->setQuery($query);
$result = $db->execute();
}
catch (RuntimeException $e){
echo $e->getMessage();
}
// for testing you can echo the query as
echo $db->replacePrefix($query);
If $array['userid'] is not defined or empty, and $date is not defined, the query most certainly would throw an error in this example
At the end, add echo $query;. This should print to the screen the SQL query that is actually being run. Post that so we can see the query, since this will help see what could be wrong.
Also, in many cases, Joomla redirects after saves to prevent a page refresh from resubmitting data. So it can be helpful to add an exit(); statement after the echo to actually see what it is echoing.
(Though as I type this, I'm guessing that the date needs to be quoted.)
Use below code after setQuery
$db->setQuery($query);
$result = $db->query();

Categories