PHP, PDO binding dynamic number of values into the statement - php

I need effective some solution for the following issue:
For some reason that would be too much time-consuming to explain properly, I need a PDO prepare statemnt sorta looking this way:
'SELECT field, another field, blabla FROM table WHERE some_foreign_id = first_val AND the_same_foreign_id = second_val AND again_the_same_id = third val ......'
and Id wish to fill the values with an array of unknown size, that depends on how many fields in that foreign table fits to a certain category in yet another table.
So the querstion is: is it even possible or should I give it up and find some naive walkaround?
Thanks in advance!
Mac

You can pass an array of values into stmt ->execute($array); The only tricky part would be getting the number of question marks to enter.
$foreign_ids = array(foreign_id_1, foreign_id_2, foreign_id_3); //etc
$input_list = substr(str_repeat(',?', count($foreign_ids)), 1); //this gets you the correct number of ? to use for your query
// if you need add another value to the parameters you can use array_push($foreign_ids,$your_other_param);
$stmt= $dbh->prepare("
SELECT field, another_field
WHERE some_foreign_id = ($input_list)");
$stmt->execute($foreign_ids);

It should be possible. You'll need to generate your query dynamically with question marks for parameters, and then bind with an array at the point of execution.
See example 3 on the PDO::execute page of the PHP docs.

Related

How to add a possble value to a MySQL SET type in php, without know the current values

Hi everybody and sorry for my english.
I have the column "example" that is a SET type.
I have to make a php page where you can add values to that column.
First of all I need to know what is just in "example", to prevent the adding of an existing value by a control. Second of all I need to add the new value.
Here's what I had thinked to do.
//I just made the connection to the db in PDO or MySQLi
$newValue=$_POST['value']; //I take the value to add in the possible values from a form
//Now I have to "extract" all the possible values. Can't think how.
//I think I can store the values into an array
$result=$sql->fetch(); //$sql is the query to extract all the possible values from "example"
//So now i can do a control with a foreach
foreach($result as $control){
if ($newValue == $control){
//error message, break the foreach loop
}
}
//Now, if the code arrives here there isn't erros, so the "$newValue" is different from any other values stored in "example", so I need to add it as a possible value
$sql=$conn->query("ALTER TABLE 'TableName' CHANGE 'example' 'example' SET('$result', '$newValue')"); //<- where $result is the all existing possible values of "example"
In PDO or MySQLi, it's indifferent
Thanks for the help
We can get the column definition with a query from information_schema.columns
Assuming the table is in the current database (and assuming we are cognizant of lower_case_table_names setting in choosing to use mixed case for table names)
SELECT c.column_type
FROM information_schema.columns c
WHERE c.table_schema = DATABASE()
WHERE c.table_name = 'TableName'
AND c.column_name = 'example'
Beware of the limit on the number of elements allowed in a SET definition.
Remove the closing paren from the end, and append ',newval').
Personally, I don't much care for the idea of running an ALTER TABLE as part of the application code. Doing that is going to do an implicit commit in a transaction, and also require an exclusive table / metadata lock while the operation is performed.
If you need a SET type - you should know what values you add. Otherwise, simply use VARCHAR type.

How to use wildcard in PHP query

I have a table filter feature in PHP club membership webpage. I made it so the user can filter the table and choose which members to display in a table. For example, he can choose the country or state where the member is from then hit display. I am using a prepared statement.
The problem is, I need to use wildcards to make the coding easier. How do I use a wildcard in PHP MySQL query? I will use wildcards for example if the user does NOT want specific country but instead he wants to display all members from all countries.
I know not specifying the WHERE country= will automatically select any countries but I already constructed it so each controls like the SELECT control for country already has a value like "CA" or "NY" and "*" if the user leaves that control under "All Countries". This value when submitted is then added to the query like:
$SelectedCountry = $_POST["country"];
sql .= " WHERE country=" . $SelectedCountry;
But the problem is using WHERE country=* doesn't seem to work. No errors, just doesn't work. Is "*" the wildcard in PHP MySQL?
The * is not a wildcard in SQL when comparing with the = operator. You can use the like operator and pass a % to allow for anything.
When doing this the % should be the only thing going to the bind. $Bind_country = "'%'"; is incorrect because the driver is already going to quote the value and escape the quotes. So your query would come out as:
WHERE country ='\'%\''
The = also needs to be a like. So you want
$bind_country = '%';
and then the query should be:
$sql = 'select * from table where country like ?';
If this were my application I would build the where part dynamically.
Using * in WHERE clause is not right. You can only give legit value. For example:
// looking for an exact value
SELECT * FROM table WHERE column = 'value'
// you can also do this when looking for an exact value
// it works even if your $_POST[] has no value
SELECT * FROM table WHERE column = 'value' OR '$_POST["country"]' = ''
// looking for a specific or not exact value
// you can place % anywhere in value's place
// % denotes the unknown characters of the value
// it works also even if your $_POST[] has no value
// results will not be the same when you're using AND or OR clause
SELECT * FROM table WHERE column LIKE '%val%'
I think below link can solve your problem.
Just have a look and choose what you need.
Thanks.
http://www.w3schools.com/sql/sql_wildcards.asp

Execute 2 mysql Queries with the second being based on the first

Hi I have two tables that I need to insert into.
the issue is that the first table has an ID field that is automatically generated and I need this field in the second query
members (table1):
|id|name|eyeColour|
assignedMembers (table 2):
|id|memberID|groupID|
I am currently using the below:
$addMember = $dbHandle->prepare("INSERT INTO members(name,date) VALUES(?,?)");
$addMember->bind_param("ss",$name,$eyeColour);
$addMember->execute();
$getID = $dbHandle->("SELECT id from members where name = ? LIMIT 1");
$getID->bind_param("s",$name);
$getID->execute();
$getID->bind_param($MID);
$assignMember= $dbHandle->prepare("INSERT INTO assignedMembers memberID,groupID) VALUES(?,4)");
$assignMember->bind_param("i",$MID);
$assignMember->execute();
This fails at the $assignMember->bind_param(); after troubleshooting I noticed that the $MID variable is empty.
it seems as though the row from the first INSERT is not added before the execution of the next statement is there a way to force this?
Thank you for taking the time to read this post, any help would be greatly appreciated
mysqli:$insert_id is what you are looking for.
$addMember = $dbHandle->prepare("INSERT INTO members(name,date) VALUES(?,?)");
$addMember->bind_param("ss",$name,$eyeColour);
$addMember->execute();
$id = $dbHandle->insert_id;
I think you should use
$getID->bind_result($MID);
$getID->fetch();
instead of
$getID->bind_param($MID);
Due to usage of '...->bind_param' I assume, you use MySQLi.
Check out: mysqli_insert_id — Get the ID generated in the last query

Using a bound parameter in Select portion of statement

I'm trying to pass a variable in the select portion of one of my mysql statements here but am not getting the desired result. Heres a snippet of my code:
if(isset($_GET['send'])) {
$send='ra_dccr.'.$_GET['send'];
}
$query = $link->prepare("SELECT locale.id, locale.provider_num, locale.provider_name, :var as ccr
FROM `ra_dccr`
INNER JOIN `locale`
ON ra_dccr.id = locale.id
WHERE locale.report_record_num LIKE concat ('%',:recordnum,'%')
$query->bindParam(':var', $send, PDO::PARAM_STR);
$query->execute();
My issue is that ccr is displaying as ra_dccr.{value of $send}
instead of the actual value that should be pulled from the database when I fetch the result. Am I actually allowed to use variables in this way in a select statement? How can I get sql to look for the appropriate column name this way. For instance if send is ct_scan, it should look for ra_dccr.ct_scan and then pull the val.
Thanks in advance
Heres an image of what is happening
No, this is not possible. Parameters are for passing values to a query. And that's what happens here: the value you pass to :var is returned literally.
If you want to use a dynamic field name, build the query using the actual field name without using bind parameters:
"SELECT locale.id, locale.provider_num, locale.provider_name, $send as ccr
The best way to do this is to verify the value of $_GET['send'] first. Maybe you can even check it against a whitelist of allowed fields.
if (!in_array($_GET['send'], array('field1', 'field3', 'field30'))) {
die('invalid field!');
}

"SELECT * FROM users WHERE id IN ( )" == FAIL

I have a function that I use called sqlf(), it emulates prepared statements. For instance I can do things like:
$sql = sqlf("SELECT * FROM Users WHERE name= :1 AND email= :2",'Big "John"','bj#example.com') ;
For various reasons, I cannot use prepared statements, but I would like to emulate them. The problem that I run into is with queries like
$sql = sqlf("SELECT * FROM Users WHERE id IN (:1)",array(1,2,3) );
My code works, but it fails with empty arrays, e.g. the following throws a mysql error:
SELECT * FROM Users WHERE id IN ();
Does anyone have any suggestions? How should I translate and empty array into sql that can be injected into an IN clause? Substituting NULL will not work.
Null is the only value that you can guarantee is not in the set. How come it is not an option? Anything else can be seen as part of the potential set, they are all values.
I would say that passing an empty array as argument for an IN() clause is an error. You have control over the syntax of the query when calling this function, so you should also be responsible for the inputs. I suggest checking for emptiness of the argument before calling the function.
Is there a possibility that you could detect empty arrays withing sqlf and change the SQL to not have the IN clause?
Alteratively, you could postprocess the SQL before passing it to the "real" SQL executor so that "IN ()" sections are removed although you'd have to do all sorts of trickery to see what other elements had to be removed so that:
SELECT * FROM Users WHERE id IN ();
SELECT * FROM Users WHERE a = 7 AND id IN ();
SELECT * FROM Users WHERE id IN () OR a = 9;
would become:
SELECT * FROM Users;
SELECT * FROM Users WHERE a = 7;
SELECT * FROM Users WHERE a = 9;
That could get tricky depending on the complexity of your SQL - you'd basically need a full SQL language interpreter.
If your prepare-like function simply replaces :1 with the equivalent argument, you might try having your query contain something like (':1'), so that if :1 is empty, it resolves to (''), which will not cause a parse error (however it may cause undesirable behavior, if that field can have blank values -- although if it's an int, this isn't a problem). It's not a very clean solution, however, and you're better off detecting whether the array is empty and simply using an alternate version of the query that lacks the "IN (:1)" component. (If that's the only logic in the WHERE clause, then presumably you don't want to select everything, so you would simply not execute the query.)
I would use zero, assuming your "id" column is a pseudokey that is assigned numbers automatically.
As far as I know, automatic key generators in most brands of database begin at 1. This is a convention, not a requirement (auto-numbered fields are not defined in standard SQL). But this convention is common enough that you can probably rely on it.
Since zero probably never appears in your "id" column, you can use this value in the IN() predicate when your input array is empty, and it'll never match.
The only way I can think to do it would be to make your sqlf() function scan to see if a particular substitution comes soon after an "IN (" and then if the passed variable is an empty array, put in something which you know for certain won't be in that column: "m,znmzcb~~1", for example. It's a hack, for sure but it would work.
If you wanted to take it even further, could you change your function so that there are different types of substitutions? It looks like your function scans for a colon followed by a number. Why not add another type, like an # followed by a number, which will be smart to empty arrays (this saves you from having to scan and guess if the variable is supposed to be an array).

Categories