CodeIgniter - implode/query binding causing unwanted string - mysql

I have the following query attempting an update in CodeIgniter:
$sql = "UPDATE fanout.manual_data
SET call_leader_id = ?
WHERE id IN (?)";
$q = $this->db->query($sql, array($leaderID, implode(", ", $empIDs)));
The implode is creating a string of all the IDs in my array. However, that is resulting in the query looking like:
UPDATE fanout.manual_data SET call_leader_id = '55993' WHERE id IN ('57232, 0097726, 0076034');
When what I need is:
UPDATE fanout.manual_data SET call_leader_id = '55993' WHERE id IN (57232, 0097726, 0076034);
Only difference, is the single quotes surrounding the string of IDs. Is this something I need to do myself and skip over CI's query bindings (http://codeigniter.com/user_guide/database/queries.html) or is something CI can handle and I'm just missing a step?
Thanks.

I don't think you can skip that behavior. You're technically passing a string, so CI interprets it as such and simply surrounds it with quotes.
I think you're better off simply concatenating the $empIDs by hand (e.g. using a foreach loop), escaping them with $this->db->escape() in case you wanna be sure.

Related

how can I avoid sql inject when using "order by case when" in Golang?

there is a param representing userName;
I need to get some sorted records,if column "starred_by" contains 'userPrefix',it should be at the front,others should be at the end.
var userPrefix string; //userPrefix is a Request Param.
usePrefix = `%` + userPrefix + `%`
if userPrefix != "" {
order := fmt.Sprintf("CASE \nWHEN starred_by LIKE %q THEN 1\nELSE 2\nEND", userPrefix)
db = db.Order(order)
}
db = db.Order(otherParam1).Order(otherParam2)
db = db.Model(***).Scan(***)
the raw sql likes below:
SELECT * FROM `***` ORDER BY
CASE WHEN starred_by LIKE "%prefix1%" THEN 1 ELSE 2 END,otherParam1,otherParam2,otherParam3
but apparently this causes sql inject problem , how can i fix this?
the way to solve sql inject.
These elements cannot be bound into JDBC and gorm doesn't support them as parameterized queries or escape them - they are dangerous to use with untrusted input.
There are two options to do this safely - ideally you should use both:
Validate the columns in these via positive / whitelist validation. Each column name should be checked for existence in the associated tables.
You should enquote the column name - adding single quotes around the columns. If you do this, you need to be careful to validate there are no quotes in the name, and error out or escape any quotes. You also need to be aware that (in most databases) adding quotes will make the name case sensitive.

Is it possible to insert sql query in php array value?

for($count = 0; $count < count($_POST["item_sub_category"]); $count++)
{
$data = array(
':item_sub_category_id'
=> SELECT r_name FROM Repair where r_id = $_POST["item_sub_category"][$count]
);
$query = "INSERT INTO Repairlog (description,visitID) VALUES (:item_sub_category_id,'1')";
$statement = $connect->prepare($query);
$statement->execute($data);
}
As far as concerns, your code won't work. The SQL query that you are passing as a parameter will simply be interpreted as a string.
You could avoid the need for a loop by taking advantage of the INSERT INTO ... SELECT ... syntax. The idea is to generate an IN clause that contains all values that are in the array, and then run a single query to insert all records at once.
Consider:
$in = str_repeat('?,', count($_POST["item_sub_category"]) - 1) . '?';
$query = "INSERT INTO Repairlog (description,visitID) SELECT r_name, 1 FROM Repair WHERE r_id IN ($in)";
$statement = $connect->prepare($query);
$statement->execute($_POST["item_sub_category"]);
Note: it is likely that visitID is an integer and not a string; if so, then it is better not to surround the value with single quotes (I removed them in the above code).
TLDR; No.
Your question can be re-framed as: Can I write SQL code in php. The answer is NO. You can write the SQL code within a String type variable (or parameter) in php.
This is a general rule for any programming language, you cannot have multiple languages within the same file, as the language parser will not be able understand which syntax is that.
In order to embed a different language in another language, you need some kind of separator that will define when the new language or special type will start and when it will end.

Insert into table SET - rows with special characters skipped

I have this query:
$sql = "
INSERT INTO table SET
name = '$name',
sku = '$number',
description = '$desc'
";
But the rows containing some special characters (in my case this ') are not inserted.. How I can solve?
Thanks in advance.
When you construct your query, you need to escape the data you are inserting.
You need to at least use addslashes() function in PHP, like this:
$sql = "INSERT INTO table SET name = '".addslashes($name)."', sku = '".addslashes($number)."', description = '".addslashes($desc)."'";
However more correct way is to use a different function than addslashes, which would properly handle all characters in the data, not only apostrophes.
I am using my custom 'escape' function like this:
function escape($text)
{
return str_replace(array('\\', "\0", "\n", "\r", "'", '"', "\x1a"), array('\\\\', '\\0', '\\n', '\\r', "\\'", '\\"', '\\Z'), $text);
}
So using this function, you would write:
$sql = "INSERT INTO table SET name = '".escape($name)."', sku = '".escape($number)."', description = '".escape($desc)."'";
You must use parameterised queries instead of manually appending those values. Currently if name, number or description would contain any sql it would get executed.
A lot more detailed answer is in How can I prevent SQL injection in PHP?
Read about escaping characters in mysql. I think it is done with \

Incrementing numerical value and changing string in SQL

I have a database that has stored values in a complicated, serialized array where one component is a string and another is the length of the characters of the string, in this format:
s:8:"test.com"
Where "s" holds the character length of the string in the quotations.
I would like to change the string from "test.com" to "testt.com", and I'm using the following statement in SQL:
UPDATE table SET row=(REPLACE (row, 'test.com','testt.com'))
However, this breaks the script in question, because it doesn't update the character length in the "s" preceding the string where "test.com" is stored.
I was wondering if there is a query I can use that would replace the string, and then also increment the value of this "s" preceding to where the replacement occurs, something like this:
UPDATE table SET row=(REPLACE (row, 's:' number 'test.com','s:' number+1 'testt.com'))
Does anyone know if this kind of query is even possible?
UPDATE table set row = concat('s:',length('testt.com'),':"testt.com"');
If you need to change exact string, then use exact query -
UPDATE table SET row = 's:9:"testt.com"' WHERE row = 's:8:"test.com"';
The string is a "serialized string".
If there are multiple strings to be replaced, it might be easier to create a script to handle this.
In PHP, it goes something like this:
$searchfor = serialize('test.com');
$replaceby = serialize('testt.com');
// strip last semicolon from serialized string
$searchfor = trim($searchfor,';');
$replaceby = trim($replaceby,';');
$query = "UPDATE table SET field = '$replaceby' WHERE field = '$searchfor';";
This way, you can create an exact query string with what you need.
Do fill in the proper code for db connection if necessary.

Propel ORM - Custom where clause

I'm trying to match md5(ID) to an id.
SELECT *
FROM `user` u
WHERE
MD5(`user_id`) = '66f041e16a60928b05a7e228a89c3799'
this is ID = 58
I tried something like this. I know I'm close I just don't know what I'm missing
$criteria = new Criteria();
$criteria->addAnd('md5('.User::USER_ID.')', $_REQUEST['fs'], Criteria::CUSTOM);
$user = UserPeer::doSelectOne($criteria);
Any ideas?
First of all, directly using Criteria objects is deprecated not recommended. You should use Active Query classes.
Using these classes, you will be able to write stuff like this :
UserQuery::create()
->where('md5(User.Password) = ?', $_REQUEST['fs'], PDO::PARAM_STR)
->findOne();
You'll notice that I use the PhpName both of the table and the column in the query.
EDIT : For raw conditions, the parameter type has to be specified. You'll find more information on this issue.
After lenghty T&E process I managed to get it done like this
$c = new Criteria();
$c->add(UserPeer::USER_ID, "md5(user.user_id) = \"".$_REQUEST['fs']."\"", Criteria::CUSTOM); // risk of SQL injection!!
$saved_search = UserPeer::doSelectOne($c);
For some reason PropelORM though that $_REQUEST['fs'] was name of the table rather than the value. \"" solved the problem.