I am trying to decipher a particular statement that is in PHP program that is doing a Mysql query. The query has ?: and ? in it. What is there function?
$data = db_get_field("SELECT data FROM ?:order_data WHERE order_id = ?i AND type = 'A'", $order_id);
Thanks for any help.
Chris
They look like placeholders for prepared statements. You provide the ? where you will later provide an actual value. Consider this example from the PHP documentation:
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (?, ?)");
$stmt->bindParam(1, $name);
$stmt->bindParam(2, $value);
Source: http://php.net/manual/en/pdo.prepared-statements.php
Your particular example appears to be from CS-Cart. For instance, according to their documentation ?i forces the value passed into that placeholder to be converted to an integer (this is similar to the way sprintf works).
$number = 9;
echo sprintf( "I have %d tasks.", $number );
// Outputs "I have 9 tasks."
In the above case, $number is treated as an integer. If I tried to pass a string into that slot, I'd get very different results:
$number = "completed";
echo sprintf( "I have %d tasks.", $number );
// Outputs "I have 0 tasks."
Note here how my types didn't match up, and therefore 0 replaced completed in the output.
Bottom line, these are placeholders.
The characters ? are : identifiers to form a parametrized queries. Later you bind values to variables and the engine performs the query for multiple values. This works faster, as the query is compiled once by server rather than compiling it for each variable=value set.
Related
I want to dynamically determine the data type of input values I am getting from my HTML input form.this will assist me to bind parameter values of data I am inserting into my database using PHP.
This information will assist me to determine the values of the string 'sss'
in the code below for MySQL prepared statement, I want to create an insert data class and the input values can be of the type 'sdib' for the types string, double,integer,or Blob.
if($stmt = $mysqli->prepare($sql)) {
$stmt->bind_param("sss", $first_name, $last_name, $email);
}
I have tried the code below and even tried some other codes in PHP manual that uses call_user_func_array() in vain.
I understand input values from HTML forms are always strings.
// SECTION USING PREPARED STATEMENT IN INSERT QUERY
if ($stmt = $mysqli->prepare($sql)) {
$stmt->bind_param("sss", $first_name, $last_name, $email);
}
//CODE SHOWING HOW I AM TRYING TO GET DATA TYPE OF HTML INPUT VALUES
if (gettype($v) === "string") {
return "s";
} elseif (gettype($v) === "float") {
return "d";
} elseif (gettype($v) === "integer") {
return "i";
} elseif (gettype($v) === "binary") {
return "b";
} else {
$e = '..could not establish data type';
$this->setError($e);
echo $e;
}
I want to be able to get datatype part 'sss' DYNAMICALLY from HTML input forms. the statement I want to construct is similar to this
$stmt->bind_param("sddsii", $first_name, $last_name, $email);
As pointed out in another answer all your values coming from HTML are strings. However, you might be having input coming from other sources, which you would like to pass to your statement. What would happen if you used string binding all the time?
Best way is to test it.
$data1 = '1';
$data2 = 2;
$data3 = '0.5-a';
$stmt = $mysqli->prepare('SELECT ?=1 AS f1, ?="2" AS f2, ?=0.5 AS f3');
$stmt->bind_param('sss', $data1, $data2, $data3); // binding string
$stmt->execute();
$row = $stmt->get_result()->fetch_assoc();
var_dump($row); // all true
In these simple examples, there is no difference. Why? Because MySQL will cast a string to appropriate type if it is used in a numeric context.
Why specify a type explicitly if almost everything can be sent as a string?
Because if you know the data type of your values, you shouldn't be casting them back and forth. If you have integers and you use them in MySQL in numeric context then there is no reason to cast them to a string in MySQLi bind_param().
Another important use case is when MySQL really makes a distinction in the types, e.g. in ORDER BY clause. If you bind a string instead of number, the order will be different. MySQL can either take an ordinal number representing the column number in SELECT or a column name(which cannot be bound) or a string literal.
$data1 = '2';
// I want the records to be ordered by `name`, which is the second column
$stmt = $mysqli->prepare('SELECT id, name FROM products ORDER BY ?');
$stmt->bind_param('i', $data1); // binding integer instead of string
Related post: mysqli_stmt::bind_param() - specify another data type than āsā for each parameter
When it comes to binary or blob, they are just binary strings. This means they have no character set, and sorting and comparison are based on the numeric values of the bytes in column values.
If you ever find yourself needing to insert a blob value, it will most likely not come from HTML form as a string, but rather from reading in a file and you will know that you need to use b.
I want to dynamically determine the data type of input values i am getting from my HTML
The "T" in HTML stands for "text". There is only one data-type in HTML, string. Any code that receives input originating from HTML must already be aware of what type of data to expect and convert the string input into that type.
If your database expects a user's age to be an Integer, for example, then when your code receives that user input (a string), it must convert it to an Integer and then that Integer can be passed into the database.
$queryString = 'SELECT * FROM n8593370.items AND Suburb = :suburb AND Name LIKE \'%:name%\'';
$stmt = $pdo->prepare($queryString);
$stmt->bindValue(':suburb', $suburb);
$stmt->bindValue(':name', $name);
$stmt->execute();
$results = $stmt->fetchAll();
I am getting the above mentioned error can not for the life of my figure out why.
I am certain I only have 2 variables to bind and that I indeed bind both.
When I perform this with each conditional on their own i.e. WHERE 1 = 1 AND Suburb = :suburb or WHERE 1 = 1 AND Name LIKE \'%:name%\' I do not have any errors.
ALTHOUGH the latter of the two conditionals does not return any results, however when I test it in MySQL Workbench it works as I expect it.
Can anybody shed some light on the issue?
When using placeholder values it's important to leave any and all escaping out of the query. The value itself should be bare, PDO will take care of the escaping for you if you're disciplined about using placeholder values.
Specify it this way:
"...name LIKE :name..."
Then you bind this way:
$stmt->bindValue(':name', "%$name%");
I'm trying to set up a dynamic MySQL query, using mysqli prepared statements. I need to compare multiple values (unknown how many) to a single column.
The following works:
$qs = '?,?';
$query = 'SELECT r_id FROM sometable WHERE someindex IN ('.$qs.')';
$statement = $db_conn->prepare($query);
call_user_func_array(array($statement, 'bind_param'), array('ss', 'Something', 'somethingelse'));
I get a result back from the DB, and can do as I please with the return. BUT, the following does not work:
$qs = '?,?';
$query = 'SELECT r_id FROM sometable WHERE someindex IN ('.$qs.')';
$statement = $db_conn->prepare($query);
$test = array('ss', 'Something', 'something else');
call_user_func_array(array($statement, 'bind_param'), $test);
With the only difference being the assignment of $test, instead of creating the array directly within call_user_func_array.
Similarly:
$one = 'pizza';
$two = 'pie';
call_user_func_array(array($statement, 'bind_param'), array('ss', $one, $two));
also does not work. The statement doesn't even execute.
If I can't put variable names directly into the statement, I can't have the dynamic queries. What's going on? Is there a fix for this, or maybe another (equally simple) way I can run a query on a single column, with an unknown number of terms? References or pointers (i.e. &$one) do not work either.
There seems to be a couple known issues with call_user_func_array back in 2012, or around there, but I can't find anything more recent. I am using PHP 5.5
EDIT 1
Known issue, back in 2007 here
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.