I have a function that takes an array and creates a SQL statement based on they key/value pairs of the array. For example:
name=>SomeKittens
It'd turn into
(`name`) VALUES ('SomeKittens')
The only problem is when I use a MySQL string function such as NOW().
creation_date=>NOW()
turns into
(`creation_date`) VALUES ('NOW()')
Note that NOW() is escaped. Is there any way to detect if the value is a MySQL string function? (besides of course $value === "NOW()")
I'm using the Joomla DBO but am open to PDO/MySQLi solutions as well.
(relevant chat discussion)
If you allow functions with arguments I don't think you will be able to protect your db against SQL injections.
If you allow only functions w/o arguments (like NOW()) you might as well hardcode a list.
You may simply want to define a constant like MYSQL_NOW that when creating your query you know to convert to a NOW() function call rather than 'NOW()' string.
Related
I've seen lots of good answers in general to the problem of NULL datetime fields, and the answer is don't use '', just put NULL directly.
That's all great, but all my MySQL queries are built up by doing a str_replace, like so:
$query = "SELECT * FROM ##t1 WHERE ##f1=##v1"
I then use table, field and value arrays with the actual content that will be replaced in
For every thing else it works 100% great
For this I can't find a way of getting a NULL in there without quotes around it
Anything obvious I'm missing?
You shouldn't use str_replace for constructing sql because actually it doesn't work 100% of the time.
Use prepared statements instead
http://php.net/manual/en/mysqli.quickstart.prepared-statements.php
An example of where str_replace fails
What if your table name, field name or data contains one of those "##" tokens? Then you are in trouble because it could get replaced with parameters, depending on what order you do your replacements.
With prepared statements the database handles all of this for you. You also get automatic escaping done correctly, query precompilation for better performance and other security protection that you and I probably haven't even thought about.
I am converting a Coldfusion website to PHP. I have a query that looks in a list of comma separated numbers to see if there is a match and then responds accordingly. This is the where statement I am currently using.
WHERE (`link_issue_category`.`Category_ID` IN (<CFQUERYPARAM value="#Category_id#" list = "yes">)
How do I write this in PHP?
CFQUERYPARAM does some validation on the value, and if possible sets up a bind parameter. You can probably just embed the value into the SQL, assuming you've already done validation / sanitization on it. The list parameter specifies that this is a comma-delimited list. You should be able to plug this list directly into the query, depending on the value type.
"WHERE (`link_issue_category`.`Category_ID` IN ($category_id)";
If your values in the list are strings, you may need to wrap them in qoutes before they go into the query.
FYI CF just creates a new prepared statement with the number of ? being the same as the length of your list behind the scene.
So if you want the same behaviour in PHP, it wouldn't be that hard really. Just dynamically create a new prepared statement, and bind them accordingly.
PHP Prepared statements: http://php.net/manual/en/pdo.prepared-statements.php
However, you could have just use regex to validate the list of values to numeric value and comma's only, and use the variable as part of the SQL statement.
Is it possible to insert MySQL functions using bindValue()? My code below just gets outputted as the string 'NOW()' instead of the function NOW() (without quotes).
$sthandler->bindValue(1, 'NOW()');
No. A query parameter substitutes only for a single constant value. For example, a numeric constant or literal string or date.
Anything else -- column names, table names, SQL keywords, functions, expressions -- must be in the SQL string at parse time.
Re your comment:
You should understand that parameters are not just a convenience to interpolate extra strings into your SQL. PREPARE is analogous to a compile phase for Java or C#, whereas EXECUTE is analogous to running the compiled code.
Prepare time is when the RDBMS does syntax checking, and also validation of references. It must give an error if you name a table that doesn't exist, or invoke a function that doesn't exist.
You can't pass table names or function calls as parameters because then the RDBMS wouldn't be able to validate those references at prepare time. You shouldn't be able to use a query parameter to change the syntax of the statement, or introduce invalid tables or functions.
So the parameter placeholder must be an irreducible syntactic element that is never an invalid reference, i.e. a single literal value -- a number or a string.
No, because placeholders in prepared statements are automatically escaped. Thus in your case it will see, that it is a string and (at least) put it in quotes 'NOW()'. Now its just a string for mysql for mysql too. You can set the current datetime using PHP
$sthandler->bindValue(1, date('c'));
I have a MySQL table with ID as a primary key and other for this matter non-important fields.
What I would like to do is delete multiple records by sending a list of IDs for deletion as a parameter to stored procedure.
I know how to do this manually (building a query directly in PHP) but I would like to avoid that and do all my SQL directly in the DB.
Tried searching SO but couldn't find any related questions. Sorry if this is a duplicate.
Thanks
In accordance to http://dev.mysql.com/doc/refman/5.1/en/faqs-stored-procs.html#qandaitem-B-4-1-17 you can't do it directly.
But I think you can try to the following trick:
Create string of you ids in php like 'id1,id2,id3'.
Use prepared statement for binding this sting on fly.
Maybe it helps.
You could try something like
DELETE FROM sometable WHERE FIND_IN_SET(idfield, #param)
no idea if this'd work (and don't have access to a mysql instance right now to test on). Basically the problem is that if you pass in a comma-separated value list into a paramter, it'll just be a string inside the sproc, and doing a WHERE id IN ('1,2,3') would fail, since that's just a simple string and not at all the same as WHERE id IN (1,2,3). The find_in_set() function should take care of that.
I gave +1 to #Marc B for clever use of FIND_IN_SET(). It won't be able to use an index, so the performance won't be good, but it should work.
Another solution that can work (but will be slow as well, because it can't use an index):
DELETE FROM sometable
WHERE CONCAT(',', param, ',') LIKE CONCAT('%,', idfield, ',%')
The solution that #Andrej L describes isn't really parameter binding, it's interpolation of a stored procedure argument into a dynamic SQL string prior to preparing it.
SET sql = CONCAT('DELETE FROM sometable WHERE idfield IN (', param, ')');
PREPARE stmt FROM sql;
EXECUTE stmt;
You can't parameterize a list of values with a single parameter, even if the parameter's value looks like a comma-separated list of integers.
Interpolation can work, and it will benefit from an index, but be careful to filter the string so it contains only numeric digits and commas. Otherwise you introduce a significant risk of SQL injection (debunking the claim that some people make that stored procedures are inherently more secure).
How can i store the value from a SELECT MySQL statement into a PHP variable?
for example:
$myvariable = SELECT * FROM X WHERE id = X
Thanks
you need to look at the php manual for the mysql/mysqli wrapper functions.
http://us3.php.net/manual/en/book.mysql.php
http://us3.php.net/manual/en/book.mysqli.php
If the code you provided was written with proper syntax (you need single/double quotes around string literals in php) your variable would contain the sql query string. You need to send that to the database via some kind of wrapper.
You may wont to search around for some general php and php/mysql tutorials.