I have a bunch of rows to have nieaktualny column (TINYINT(1)) modified from 0 to 1 for all rows with email_1 field equal to values from array $sprawdzone_temp. I have tried many approaches, via exec(), prepare(), execute() but none seems to work and I just have no idea why. No errors pop up when try/catching. When I am using phpMyAdmin, the queries work just fine.
Here's my PHP:
$sql = "UPDATE database.table SET `nieaktualny` = '1' WHERE `email_1` LIKE ?";
$stmt = $db->prepare($sql);
foreach($sprawdzone_temp as $email) {
$stmt->execute(array($email));
}
The array with data is fine, there seems to be something wrong with how I want to use PDO.
I suspect that your $sprawdzone_temp might not have the SQL Wildcard Characters
A wildcard character is used to substitute any other character(s) in a string.
Wildcard characters are used with the SQL LIKE operator. The LIKE operator is used in a WHERE clause to search for a specified pattern in a column.
There are two wildcards used in conjunction with the LIKE operator:
(%) - The percent sign represents zero, one, or multiple characters
2 . (_) - The underscore represents a single character
Therefore your code should be along these lines :
<?php
$sprawdzone_temp = "%".$sprawdzone_temp."%";
$sql = "UPDATE database.table SET `nieaktualny` = 1 WHERE `email_1` LIKE ?";
$stmt = $db->prepare($sql);
foreach($sprawdzone_temp as $email) {
$stmt->execute(array($email));
}
if(!$stmt){
echo "\nPDO::errorInfo():\n";
print_r($db->errorInfo());
}
?>
Update
I would suggest that you also try the SQL IN Operator, which allows you to specify multiple values in a WHERE clause.
The IN operator is a shorthand for multiple OR conditions.
<?php
$sprawdzone_temp = array($nadawca);
$in = str_repeat('?,', count($sprawdzone_temp) - 1) . '?';
$sql = "UPDATE database.table SET `nieaktualny` = 1 WHERE `email_1` in($in)";
$stmt = $db->prepare($sql);
$stmt->execute($sprawdzone_temp);
if (!$stmt) {
echo "\nPDO::errorInfo():\n";
print_r($db->errorInfo());
} else {
echo "record updated";
}
?>
tl;dr
I had to apply strip_tags to the emails that were later used in PDO query.
The issue was not in anything related to queries. The emails from the $sprawdzone_temp array were not prepared properly. When I print_r'ed the array, it looked normally, there was simply the proper email address without any spaces or similar. When I copy-pasted them from the print_r to phpMyAdmin, queries worked fine, but seemingly there was some illegal character that was interrupting the LIKE condition of SQL queries.
I have fixed that when I have randomly tried applying strip_tags when inserting the email addresses into the $sprawdzone_temp array. Now it works. Just out of curiosity - can I somehow print all the characters in a avalue - just to check what character was in there that caused the PDO query to stop?
Related
This question already has answers here:
Use an array in a mysqli prepared statement: `WHERE .. IN(..)` query [duplicate]
(8 answers)
Closed 11 months ago.
I'm trying to create a select query with dynamic where clause and dynamic parameters but I always get error :
Warning: mysqli_stmt::bind_param(): Number of elements in type
definition string doesn't match number of bind variables
Which I sincerely do not understand since it seems the count is alright. So this is what the code really looks like in its rude format. I can't see what I'm doing wrong.
//get variables
$mediaArray ='Facebook,Twitter,Twitch,';
$otherMedia = 'House';
//convert string to array
$socialArray = explode(',', $mediaArray)
//declare some variables to be used later
$andwhere = '';
$bp = '';
$socialmarray = ''
//get every value from array of social media
foreach($socialArray as $socialmedia){
$socialmarray .=$socialmedia.',';
$andwhere .= " AND socialmedianame=?";
$bp .='s';
}
//test strings
echo $wheres = $andwhere;//AND socialmedianame=? AND socialmedianame=? AND socialmedianame=?
echo $bip = $bp.'s';//ssss
echo $validarayy = rtrim($socialmarray,',');//Facebook,Twitter,Twitch
//select query
$selectquery = $conn->prepare("select * from mediaservices where socialmedianame=? $wheres");
$selectquery->bind_param("$bip",$otherMedia,$validarayy);
$selectquery->execute();
$resultquery = $selectquery->get_result();
Because:
You are using user-supplied data, you must assume that your query is vulnerable to a malicious injection attack and
the amount of data that is to be built into the query is variable/indefinite and
you are only writing conditional checks on a single table column
You should use a prepared statement and merge all of the WHERE clause logic into a single IN statement.
Building this dynamic prepared statement is more convoluted (in terms of syntax) than using pdo, but it doesn't mean that you need to abandon mysqli simply because of this task.
$mediaArray ='Facebook,Twitter,Twitch,';
$otherMedia = 'House';
$media = array_unique(explode(',', $mediaArray . $otherMedia));
$count = count($media);
$conn = new mysqli("localhost", "root", "", "myDB");
$sql = "SELECT * FROM mediaservices";
if ($count) {
$stmt = $conn->prepare("$sql WHERE socialmedianame IN (" . implode(',', array_fill(0, $count, '?')) . ")");
$stmt->bind_param(str_repeat('s', $count), ...$media);
$stmt->execute();
$result = $stmt->get_result();
} else {
$result = $conn->query($sql);
}
foreach ($result as $row) {
// access values like $row['socialmedianame']
}
For anyone looking for similar dynamic querying techniques:
SELECT with dynamic number of LIKE conditions
INSERT dynamic number of rows with one execute() call
In your query:
$selectquery = $conn->prepare("select * from mediaservices where socialmedianame=? $wheres");
The ? represents one parameter to pass in, and the evaluation of $wheres adds another three, giving you four total parameters.
bind_param() should take a string representing the types of the variables to insert as the first parameter, and the variables themselves as the subsequent parameters.
In your bind:
$selectquery->bind_param("$bip",$otherMedia,$validarayy);
$bip evaluates to ssss and $otherMedia is a single string ("House"). You might expect $validarayy to be three strings, but rtrim() returns a string. Thus, it is only one string ("Facebook,Twitter,Twitch"). You pass through two variables when the query is expecting four:
$conn->prepare("select * from mediaservices where socialmedianame=House AND socialmedianame=Facebook,Twitter,Twitch AND socialmedianame=? AND socialmedianame=? AND socialmedianame=?"
To correct this, you'll want to convert $validarayy back to an array, and use the index for the various inputs:
$socialmarray2 = explode(',', $validarayy);
$selectquery->bind_param("$bip", $otherMedia, $socialmarray2[0], $socialmarray2[1], $socialmarray2[2]);
Also note that your sample code has a few missing semicolons; you'll need to fix these in order for your code to work correctly.
This can be seen working here.
Finally, note that even if you were to split the three strings out correctly, the selection of ... AND socialmedianame=Facebook AND socialmedianame=Twitter AND socialmedianame=Twitch will never match any results; socialmedianame can only contain one value. You're probably looking to substitute your AND statements with OR statements.
I have a HTML form, from which a PHP script extracts values, as shown below:
$dbc = mysqli_connect("all required info here...") or die("Error occurred");
$sent = "Any sentence here...which may contain apostrophe or double quotes or both";
$query = "SELECT * FROM myrecord WHERE sentence = '$sent'";
$result = mysqli_query($dbc, $query);
$data = mysqli_fetch_array($result);
mysqli_close($dbc);
The problem is, that the variable $sent can contain any string with a combination of either apostrophe or double quotes or both. This gives an error when going for execution of mysqli_query().
So even if I escape double quotes in initialization of $sent it will still create problem for execution of mysqli_query(). And if I escape both for ' and " then value of $sent does not remains what it actually needs to be (although I am not sure about whether escaping both ' and " will work or not).
Is there any built in function that automatically escapes all special characters of a string? Or any workaround that solves this problem?
[P.S. I have already searched some previous questions on stackoverflow and haven't been able to find a solution.]
What you want, and what you should do is used prepared statements (parameterized queries). With PDO, that would look something like this:
$stmt = $pdo->prepare('SELECT * FROM myrecord WHERE sentence = :sentence');
$stmt->execute([':sentence' => $sentence]);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
//do stuff
}
mysqli supports them, too, but the API is slightly more cumbersome (IMO) - see mysqli_prepare docs for details:
$stmt = $mysqli->prepare('SELECT * FROM myrecord WHERE sentence = ?');
//or $stmt = mysqli_prepare($connection, $query);
Then, you bind the parameter (the value to be used in the WHERE clause) using bind_param:
$stmt->bind_param('s', $sentence);
//or mysqli_stmt_bind_param($stmt, 's', $sentence);
Then call execute - or mysqli_stmt_execute, and fetch the results using fetch - or mysqli_stmt_fetch...
As mentioned in the comments: the parameters and query string needn't be quoted in any way, because they're treated as separate entities. The result being that you can re-use the same prepared statement with different paramters:
$stmt = $pdo->prepare('SELECT * FROM table WHERE field = :field');
$fieldVals = [123, 46, 32]; // three values:
$results = array_fill_keys($fieldVals, null);
foreach ($fieldVals as $val) {
$stmt->execute([':field' => $val]);//execute with each value in $fieldVals array
$results[$val] = $stmt->fetchAll(PDO::FETCH_ASSOC); // fetch results for this field value
//optional, but good form:
$stmt->closeCursor();
}
you've now used the same statement 3 times, but only had to send the query string once. The query had to be parsed and processed once, and after that, you merely sent the paramters to the DB. This approach is generally faster, safer (prepared statements protect agains most injection attacks), and just all round better.
I'm trying to insert a PHP function into a foreach loop in order to generate values for each row fetched from the db for the variable $Match.
The db query itself works properly, and the function which assigns values to variable $Match works properly when I test it with hard-coded values, but when I try combining it with the rest of the code in order to use db values it stops working properly. Specifically: 1) It only runs the first IF statement; and 2) If that statement is true, it's adding the same value for every row.
I've uploaded a functional example with hard-coded values to this sandbox http://sandbox.onlinephpfunctions.com/code
Declaring values for test case:
$User_Waist = "26";
$User_Hip = "38";
$Match = Null;
$waistMatch = Null;
$hipMatch = Null;
Query database & fetchAll
$stmt = $conn - > prepare("SELECT * FROM SizeChart WHERE FIND_IN_SET($User_Waist, Waist_Measurement) > 0 OR FIND_IN_SET($User_Hip, Hip_Measurement) > 0;");
$stmt - > bindValue(':Waist_Measurement', $Waist_Measurement, PDO::PARAM_STR);
$stmt - > bindValue(':Hip_Measurement', $Hip_Measurement, PDO::PARAM_STR);
$stmt - > execute();
$rows = $stmt - > fetchAll(PDO::FETCH_ASSOC);
Loop through results
$count = 0;
foreach($rows as $row) {
$count++;
Adds value to variable $Match
if (strpos($row['Waist_Measurement'], $User_Waist) !== false) {
$waistMatch = 'waistFit';
}
if (strpos($Hip_Measurement, $User_Hip) !== false) {
$hipMatch = 'hipFit';
}
$Match = $waistMatch.', '.$hipMatch;
Display Results
echo "Size #: ".$row['Size']."; Fit Matches: ".' '.$Match."; Waist: ".$row['Waist_Measurement'], "; Hip: ".$row['Hip_Measurement'], ".<br />";
The SQL text doesn't contain bind placeholders :Waist_Measurement or :Hip_Measurement.
The bindValue calls aren't going to work, since there's no placeholder of the specified name to bind a value to.
Here's an example that uses a bind placeholder named :fum. Note that this string appears both in the SQL text and as an argument to bindValue or bindParam.
$foo = "bar";
$sql = "SELECT fee FROM fi WHERE fo = :fum ";
// ^^^^
$sth = $dbh->prepare($sql);
$sth->bindValue(":fum", $foo, PDO::PARAM_STR);
// ^^^^
$sth->execute();
FOLLOWUP
This is the SQL text in your prepare.
(I notice that there's a semicolon at the end of the SQL text, and that may be causing an error; I normally don't include a trailing semicolon in my SQL text.)
SELECT *
FROM SizeChart
WHERE FIND_IN_SET($User_Waist, Waist_Measurement) > 0
OR FIND_IN_SET($User_Hip, Hip_Measurement) > 0
But the point is that there aren't any bind placeholders in that SQL text. When you do a:
->bindValue(":Waist_Measurement",...
^^^^^^^^^^^^^^^^^^
That's essentially saying "Hey! There's a string literal ':Waist_Measurement' in the SQL text of the prepared statement", and saying "in place of that string literal, use this value...".
But the thing is, that string literal does not appear in your SQL text. There's no bind placeholder in the statement. (There's not even a placeholder of a different name, I don't see any colon characters anywhere in the SQL.)
I'm surprised that PDO isn't throwing an error. Actually, PDO probably is throwing an error, but your code is ignoring it. If your code isn't going to check the return from prepare, execute, et al. then you can have PDO do the check and throw the exception for you, by specifying an attribute on the connection.
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Also...
The inclusion of PHP variables $User_Waist and $User_Hip is a little unusual in a prepared statement. One of the benefits of prepared statements is that variables representing values can be replaced with bind placeholders.
(I'm confused by what you are trying to do, I can't tell you how to fix it.)
My prepared query looks like this:
$sql = "SELECT $t1.id FROM $t1 WHERE $t1.name IN (?)";
When I try:
$stmt = Sql::$select->prepare($sql);
$string="'aaa','bbb','ccc'";
$stmt->bind_param('s', $string);
...it doesn't return the expected results. It treats the string as one name and not many separate names. How can it be solved?
The rest of the function:
$stmt->execute();
$stmt->store_result();
return $stmt;
Try altering query like this
$sql = "SELECT $t1.id FROM $t1 WHERE FIND_IN_SET($t1.name, ?)>0";
$stmt = Sql::$select->prepare($sql);
$string='aaa,bbb,ccc';
$stmt->bind_param('s', $string);
And this solution is not reliable.
Please see FIND_IN_SET(str,strlist)
Correct method is to use separate placeholders for each element in the IN statement.
Another suggestion, get rid of the IN statement and run through a loop in php to generate the query and bind the params.
The problem is that the bind_param function with 's' threats the parameter as a single string, so it is basically transforming your query to:
"SELECT $t1.id FROM $t1 WHERE $t1.name IN (''aaa','bbb','ccc'')";
A quick fix would be to change the string variable to:
$string="aaa','bbb','ccc";
Note: without the leading/trailing quotes (you can make this using trim($string, "'")
You may also try inverting the quotes: using " instead of ' if this does not work.
A more reliable and robust solution is to change the query to incude a ? for each string (using arrays with expolode() / implode() php functions.
I am trying to insert values in database and values are not being inserted, here is the code i have:
$user_name = "username";
$password = "password";
$database = "database";
$server = "localhost";
$db_handle = mysql_connect($server, $user_name, $password);
$db_found = mysql_select_db($database, $db_handle);
if ($db_found) {
$SQL = 'INSERT INTO table (anInt, DomainName, URL, Rank, PageRank, Google, Bing, Boss, IndexedPage, Backlinks) VALUES ($anInt, $Domain, $URL, $Rank, $Pagerank, $Google, $Bing, $Yahoo, $Pages, $backlinks)';
$result = mysql_query($SQL);
mysql_close($db_handle);
print "Records added to the database";
it is printing that records added to the database but when looking at the database nothing is being added. some of the values are doubles, text, and ints. Is there anyway to debug this? I will be adding more information to the post if someone asks me to.
and of course I have an else statement i just thought it is not relevant since it is telling me that records are added.
First of all, you should escape the string values you are passing into the SQL query, using mysql_real_escape_string.
Then, you should add quotes, in your SQL query, arround the fields that are meant to contain strings.
I don't really know which fields are integers and which fields are strings, but you should be using something like this to build your SQL query :
// Escape the string data, and make sure integer really contain integers
$anInt = intval($anInt);
$Domain = mysql_real_escape_string($Domain);
$URL = mysql_real_escape_string($URL);
$Rank = intval($Rank);
$Pagerank = = intval($Pagerank);
$Google = intval($Google);
$Bing = intval($Bing);
$Yahoo = intval($Yahoo);
$Pages = intval($Pages);
$backlinks = intval($backlinks );
// Build the SQL query, using the "safe" variables
$SQL = 'INSERT INTO table (anInt, DomainName, URL, Rank, PageRank, Google, Bing, Boss, IndexedPage, Backlinks)
VALUES ($anInt, '$Domain', '$URL', $Rank, $Pagerank, $Google, $Bing, $Yahoo, $Pages, $backlinks)';
This is supposing that only DomainName and URL are meant to contain strings -- you might have to use mysql_real_escape_string and add quotes arround the values for some other fields too, if needed.
Then, you should take a look at the return value of mysql_query : for an insert query, in case of an error, it'll return false.
Here, if your $result variable is false, you should use mysql_error and mysql_errno : they'll allow you to know what error happened -- it will help detecting errors in your SQL query, for instance.
If this doesn't solve the problem, you should try outputting the SQL query, and run it using something like phpMyAdmin, to make sure it's OK.
I am no PHP expert, but I have 2 remarks.
You don't check the error (perhaps with mysql_errno()) so you don't know whether the records were added
I think the values, if they are strings, should be given like
'$Domain'
that is, escaped with ' characters.
better would be, of course, using something like
$sql = sprintf("INSERT ... VALUES(%d, '%s', '%s',...)",
$anInt, mysql_real_escape_string($Domain), ...);
if you insert user-supplied input.
You could examine the $result:
$result = mysql_query($query);
if (!$result) {
print "An error occured: " . mysql_error() . "\n";
}
My guess is that you're passing a string without quotes, like:
VALUES (Hello)
where you should pass it like:
VALUES ('Hello')
Like the commenter said, if the user can control these strings, you are open to an SQL Injection attack. You can prevent that attack by escaping the strings, for example:
$query = sprintf("INSERT INTO table (DomainName) VALUES ('%s')",
mysql_real_escape_string($domain_name));
In SQL queries, you need to enquote strings correctly, or it will produce an error. So all your variables that are used to store non-int or non-boolean values in the database need quotes around the values.
Additionally you should make sure that SQL injections are not a problem by escaping all values with mysql_real_escape_string first.
Apart from sql injections your error handling is not complete...
if (!$db_found) {
echo "datbase not found.";
}
else {
$SQL = 'INSERT INTO
table
(...)
VALUES
(...)
';
$result = mysql_query($SQL, $db_handle);
if ( !$result ) {
echo "error: ", mysql_error($db_handle);
}
else {
print "Records added to the database";
}
}
mysql_close($db_handle);
In case a query causes an error mysql_query() return FALSE and mysql_error() will tell you more about the error.
Well there are security issues with the code but to address one problem
you are not enclosing your string values in quotes in the SQL statement.
First of all, please regard everybody else's advice on safe database handling and avoiding injection.
The reason your query isn't doing anything is probably that you enclosed the string in single quotes. In PHP single quotes enforce the string to be literal. Unlike when using double quotes, variables will NOT be substituted. So '$foo' represents the sequence of characters '$'.'f'.'o'.'o'. "$foo" on the other hand represents the sequence of characters of whatever the variable $foo contains at the time of the string's definition.
You can use mysql_error() to catch most problems with MySQL. Even if the message isn't helping you, you at least know whether the query was parsed properly, i.e. on which end of the connection the problem lies.