Protecting wordpress - How to used wodb->prepare() function - php

I am set up the below sql with $wpdb->prepare. Currently this query is run in a function, and all the variables are passed to the function from my page.php file in wordpress. The below query works. However my question is do I need to use the %s on my variables for $field1, $field2, etc... If so can someone help me with how to set it up, it did not work when I tried. If not, could someone tell me why not? Thank you!
$query = $wpdb->prepare("SELECT DISTINCT wp_eva_geography.$field1, wp_eva_geography.$field2
FROM wp_eva_geography
WHERE wp_eva_geography.$field3=%s AND wp_eva_geography.$field4=%s",$type,$geo_no_dash);
$results = $wpdb->get_results( $query );

Use the reference document to find out how it works.
In your specific case it might be worth just echo-ing out the MySQL query string so you can see what it's actually trying to request. Then you can spot if something has gone wrong, like a bad column name or value entry.
http://codex.wordpress.org/Class_Reference/wpdb
$wpdb->query(
$wpdb->prepare(
"DELETE FROM $wpdb->postmeta
WHERE post_id = %d
AND meta_key = %s",
13, 'gargle'
)
);

Related

Wordpress PHP variables in get_results()

I have a function that works fine when I say
$results = $wpdb->get_results(
"SELECT meta_value
FROM wp_woocommerce_order_itemmeta
WHERE order_item_id = '21'
AND meta_key = '_qty"
);
This function returns 4, which is the correct number I would be looking for in my database.
Unfortunately, this code is returning an empty array to get_results(). There is something wrong in my code with passing a variable to $wpdb, does anyone have an idea?
$results = $wpdb->get_results(
"SELECT meta_value
FROM wp_woocommerce_order_itemmeta
WHERE order_item_id =" .$order_item_id.
"AND meta_key = '_qty'"
);
In this specific case I think it is a simple issue of missing white-space in your string concatenation. However there may be a more suitable way to prepare your statement that would have prevented this by making it easier to spot, and follows other good query building practices
Wordpress Prepared Statments
By using $wpdb->prepare() you can use (most of) the sprintf () syntax to help you build your query.
$query = $wpdb->prepare("SELECT meta_value
FROM wp_woocommerce_order_itemmeta
WHERE order_item_id = %d
AND meta_key = '_qty'", $order_item_id);
$results = $wpdb->get_results($query);
More info available at the wordpress codex and on prepared statements in general

What are the possible reason of WordPress database error: [Query was empty]?

I have run into error below but it seems like I can't get proper error logs.
WordPress database error Query was empty for query made by
I had this codes that will throw almost similar to the error above.
$query_select = $wpdb->get_results($wpdb->prepare(
" % "
, 1
),ARRAY_A);
My question is, what are the possible codes that will throw query was empty like in my above code.
There are some of the possible ways to get these type of error. The below usage may or may not be useful to you.
Using the $wpdb Object
1st Method - Declaring $wpdb as global and using it to execute an SQL query statement that returns a PHP object
global $wpdb;
$results = $wpdb->get_results( 'SELECT * FROM wp_options WHERE option_id = 1', OBJECT );
2nd Method - Utilizing the $GLOBALS superglobal. Does not require global keyword ( but may not be best practice )
$results = $GLOBALS['wpdb']->get_results( 'SELECT * FROM wp_options
WHERE option_id = 1', OBJECT );
Some users asked these type of question in stack exchange link below
To refer:
Another link to refer
The $wpdb->prepare method performs this functionality for WordPress, which supports both a sprintf()-like and vsprintf()-like syntax.
The %s (string), %d (integer) and %f (float) formats are supported.
All % characters inside SQL string literals, including LIKE wildcards, must be double-% escaped as %%.
So if we debug your code we like this:
$sql = $wpdb->prepare(" % ", 1);
die( var_dump($sql) );
The result will be: string ' ' (length=1)
OMG an empty string! So that's why we see the query was empty error.
The prepare method is expecting the format string to contain any of the following; %d, %s, or %f. So if you want your SQL query to be 1 you would need to change you code to:
$query_select = $wpdb->get_results( $wpdb->prepare('%d', 1), ARRAY_A );
Or if you want your SQL to be % you would need escape it with another % like this:
$query_select = $wpdb->get_results( $wpdb->prepare('%%', 1), ARRAY_A );
You can find out more about the prepare method and placeholders here Class Reference/wpdb « WordPress Codex
When we execute wp db query it's change properties in last query.
I am not understand your question but following below code if this helpful for you.
global $wpdb;
$wpdb->get_results( $wpdb->prepare(" % " , 1 ) );
if( $wpdb->last_error ){
//print_r( $wpdb->dbh)
$dbh = $wpdb->dbh;
echo $dbh->errno; // if no == 1065 then query was empty
echo $dbh->error; // Query was empty
}
https://codex.wordpress.org/Class_Reference/wpdb
see the examples.
Prepare must have a valid sql query with placeholders for variables you want in your query:
$wpdb->prepare(
"
SELECT sum(meta_value)
FROM $wpdb->postmeta //valid sql statements here
WHERE meta_key = %s
",
$meta_key)
meanwhile your code does nothing:
$wpdb->prepare(
" % " //no sql statements here
, 1 ...)
it looks like you wanted to
select * from someTable where someField % 1 -- (it will return no rows)
so, any empty query will return this error.

How to SQL query by post title in wordpress when title has an apostrophe

I'm creating a shortcode in wordpress where the user can use the post title or slug of a post to pull information from a post. Everything works well except for when a post's title has an apostrophe in it.
An example of the shortcode that works with the post slug is
[card]hunters-mark[/card]
When I use the post title and the title has a apostrophe it doesn't work.
[card]Hunter's Mark[/card]
When I use the shortcode with the title of a post that doesn't contain a apostrophe everyting works so the issue is with the apostrophe. The code I use to get the post id is
$sql="select * from $wpdb->posts where (post_title='$content' or post_name='$content' ) and post_type='cards' and post_status='publish' limit 0,1";
$my_posts = $wpdb->get_results($sql);
if( $my_posts ) {
$card_id = $my_posts[0]->ID;
}
Edit:
So what is weird is that when I try to output everything by using
`$data=strpos($content,"'");
var_dump($data);
$content=str_replace("'", "\'", $content);`
It is displaying strpos("Hunter's Mark","'")=false
So it is saying that there is no ' even though there is, and and I check the database and the post title is showing exactly how I have it in the shortcode.
Apparently you cannot autoescape quotes. You need to do that yourself:
$sqlContent = mysqli_real_escape_string($content);
I would also advise using curly brackets for variables.
$sql="select * from {$wpdb->posts} where (post_title='{$sqlContent}' or post_name='{$sqlContent}' ) and post_type='cards' and post_status='publish' limit 0,1";
$my_posts = $wpdb->get_results($sql);
...
UPDATE
You can do it another (safer) way:
$wpdb->get_results(
$wpdb->prepare(
"SELECT * FROM {$wpdb->posts} WHERE
(post_title=%s OR post_name=%s)
AND post_type='cards' AND post_status='publish'
LIMIT 0,1",
$content,
%content
)
);
you should use mysql_real_escape_string($content) before using it in your query , or even better use prepared statements to make things much safer, currently you are vulnerable to sql injection. If you use prepared statement this issue will be resolved and it will be safer for you as well.
https://codex.wordpress.org/Class_Reference/wpdb#Protect_Queries_Against_SQL_Injection_Attacks
You should use the $wpdb->prepare() method to correctly insert and escape your variables - it protects against SQL injections as well. Using %s in your SQL will indicate that you want to use a string, otherwise a %d would be used for a digit. It's also recommended to use curly braces around {$wpdb->posts}. Since you are just looking for a single row you might want to use get_row() instead of get_results() as well. If you just want the ID you should use get_var() with SELECT ID.
global $wpdb;
// set up the SQL statement
$sql = "SELECT * FROM {$wpdb->posts} WHERE ( post_title=%s OR post_name=%s ) AND post_type='cards' AND post_status='publish' LIMIT 0,1";
// replace %s with $content
$query = $wpdb->prepare( $sql, $content, $content );
// query for results
$my_post = $wpdb->get_row( $query );
// did we get a result?
if ( ! empty( $my_post ) ) {
// get the ID
$card_id = $my_post->ID;
}

PHP/MySQL - Updating an SQL table with data from another table

In a worker shift monitoring/accounting system I've built, there is an option to delete Staff Members. This works fine but I would like to archive shifts for staff members who are deleted.
I looked into it and it seemed the best way to do this would be to update my shift table, before the delete, into another table. I looked up how to do this via another Stack Overflow post however I'm getting an error: fatal error call to member function on a non-object.
Based on what I can find, this error is caused when you try to pass a null value, which has left me confused as the value I'm trying to pass is a GET and is working fine when I test it.
$sql = "
UPDATE table_archive
SET table_shift.shift_date = table_archive.shift_date,
table_shift.start_time = table_archive.start_time,
table_shift.end_time = table_archive.end_time,
table_shift.total_hours = table_archive.total_hours,
table_shift.rate_of_pay = table_archive.rate_of_pay,
table_shift.uniqueid = table_archive.uniqueid,
table_shift.addedBy = table_archive.addedBy,
table_shift.paidRate = table_archive.paidRate,
table_shift.totalPaid = table_archive.totalPaid
FROM table_shift, table_archive
WHERE table_shift.uniqueid = ?
";
$stmt = $connection->prepare($sql);
$deleteid = htmlentities($_GET['id']);
$stmt->bind_param('s', $deleteid);
$stmt->execute();
I'm stuck as to why this wont pass, the GET cant be a null value as the test delete I'm using at the moment passes the same variable and works fine. mysqli_query($connection,"DELETE FROM table_staff WHERE uniqueid='$deleteid'")
It may be that I'm using the SQL code wrongly or there is some silly thing I've forgotten but this has me stumped. Failing to fix this code, any other suggestions as to how to achieve the intended function are welcome.
You can't UPDATE FROM. Your syntax is wrong.
Instead, use this:
INSERT INTO table_archive
SELECT * FROM table_shift WHERE table_shift.uniqueid = ?
Is the use of bindParam correct?
If you use a ? it should look like this:
SELECT ...
WHERE column_name = ?
$sth->bindParam(1, $value_in_php, PDO::PARAM_INT);
If it's not ? but :param_name use this:
SELECT ...
WHERE column_name = :param
$sth->bindParam(':param', $value_in_php, PDO::PARAM_INT);
Your error sounds not like an SQL error, but a PHP error.
And if you want to update the table_archive table the SQL doesn't look correct. It should imho be like this:
UPDATE table_archive
SET table_archive.shift_date = table_shift.shift_date
, to_table_that_should_be_updated = from_table_with_value_to_update
FROM table_shift
WHERE table_shift.uniqueid = ?

passing variable with multiple values seperated by comma to sql statement through PHP

I've looked all over the interwebs, and cannot find that simple answer I'm looking for - possibly because it doesn't exist, but.. possibly because I don't know the correct terms to search for.
ok, so, i've got a variable - it's actaully a key value pair in an array that i'm passing into my function. the key is args[comments_mentioned] and the value is dynamically generated for me - it's ALWAYS going to be number, separated by commas (i.e. 1,2,3,4,5)
so, just to be super clear:
$args[comments_mentioned] == "1,2,3,4"; //could be any amount of number, not just 1,2,3,4,5
i'd like to pass this into a sql statement as a variable to use in an "IN" clause, like so:
$sr_sql = <<<SQL
SELECT *
FROM $wpdb->commentmeta
WHERE meta_value = %s
AND comment_ID in ($args[comments_mentioned])
ORDER BY meta_id DESC
SQL;
Then, Prepare it using the wordpress prepare and get results
$sr_query = $wpdb->prepare( $sr_sql, $args[user_id]) );
//receive the correct sql statement, and plug 'er in.
$sr_comment_rows = $wpdb->get_results($sr_query);
and run my foreach loop:
foreach ($sr_comment_rows as $sr_comment) {
$sResults .= 'do something with $sr_comment';
}
now, i realize the code above won't work - i can't just pass the variable in there like that. BUT, i can't pass it as a string (%s), because it wraps it in '1,2,3,45', and so it looks for the entire string, and not each number. I can't pass it as an int (%d), because of the commas...
In other posts, they mentioned create a temp table or variable, but, i'm not sure if that's the correct way to do it in mysql, or how to reference it once I do.
so, how do I do this? preference for actual code that works ;)
Thank you for reading and helping out!
One option, if you cannot normalize your data, is to enclose your string in commas such that it be ",1,2,3,4," and then you could do:
AND LOCATE( CONCAT(',',comment_ID,',') , ($args[comments_mentioned]) )
which will match if it finds a eg. ',3,' in ',1,2,3,4,' (Using 3 as an example)
I believe this should be enough:
$params = $args[comments_mentioned];
$table = $wpdb->commentmeta;
$sr_sql = "
SELECT *
FROM $table
WHERE meta_value = %s
AND comment_ID in ($params)
ORDER BY meta_id DESC
";
It will be result something like:
SELECT *
FROM table_on_variable
WHERE meta_value = %s
AND comment_ID in (1,2,3,4)
ORDER BY meta_id DESC
If your mainly issue is regarding the in clause, so you will not have problems if you use double quotes and single variable as illustrated above.

Categories