Using WHERE CONCAT with Active Record in CodeIgniter - php

The raw query I'm trying to get plugged in here is:
SELECT * FROM x WHERE CONCAT(y, ' ', x) LIKE '%value%';
I've checked through the AR docs and can't find anything that would allow me to do this. I'm not very familiar with how exactly it's constructing these queries, and was hoping someone could point me in the right direction. Thanks a bunch.

If you want to use the AR class you need to pass FALSE as third parameter to avoid the query being escaped automatically. You are now left to escaping the argument by yourself:
$value = $this->db->escape_like_str($unescaped);
$this->db->from('x');
$this->db->where("CONCAT(y, ' ', x) LIKE '%".$value."%'", NULL, FALSE);
$result = $this->db->get();
Refer to point 4) in the Active Record session of the manual. Quoting:
Custom string:
You can write your own clauses manually:
$where = "name='Joe' AND status='boss' OR status='active'";
$this->db->where($where);
$this->db->where() accepts an optional third parameter. If you set it to FALSE, CodeIgniter will not try to protect your field or table names with backticks.
$this->db->where('MATCH (field) AGAINST ("value")', NULL, FALSE);
An easier way, imho, whould be to run a "regular" query and take advantage of binding:
$result = $this->db->query("CONCAT(y, ' ', x) LIKE '%?%'", array($value));

Or use an associative array method without using the third parameter:
$a = array(
'CONCAT(`y`, " ", `x`)' => $value,
'title' => $title,
...
);
...
$this->db->like($a);
Will be generated WHERE part of the query:
... WHERE CONCAT(`y`, " ", `x`) LIKE '%test value%' AND `title` LIKE '%test title%' AND ...
Obviously useful when using more than one search parameters.

something like this should work:
$this->db->where("CONCAT(y, ' ', x) LIKE '%value%'");
$this->db->get(x);

This is old but...
You can try this:
$this->db->like('CONCAT(field_name," ",field_name_b)',$this->db->escape_like_str('value'));

Related

SQL bug or something else?

I have made a simple amateur component in Joomla...
In it there is a select>option drop-down list, which add parameters to the URL.
The problem was that it did not worked with 1.1 value and it works with a 1.5 value.
A friend of mine fixed the problem, but I want to know why it happened
Original Query:
$query = "SELECT * FROM `TABLE 2` WHERE Power='".$_GET["Power"]."' AND Poles='".$_GET["Poles"]."'";
The new working query:
$query = "SELECT * FROM `TABLE 2` WHERE Power=".floatval($_GET["Power"])." AND Poles='".$_GET["Poles"]."'";
If you're using Joomla, you should really be sticking to Joomla's coding standards and methods for everything, this includes database queries:
https://docs.joomla.org/Selecting_data_using_JDatabase
You should also be using JInput instead of $_POST or $_GET calls:
http://docs.joomla.org/Retrieving_request_data_using_JInput
Looking at your query, it should looking something like this:
$db = JFactory::getDbo();
$input = JFactory::getApplication()->input;
$power = $input->get('Power', '', 'RAW');
$polls = $input->get('Pols', '', 'RAW');
$query = $db->getQuery(true);
$query->select($db->qn(array('*')))
->from($db->qn('#__table'))
->where($db->qn('Power') . ' = ' . $db->q($power), 'AND')
->where($db->qn('Polls') . ' = ' . $db->q($polls));
$db->setQuery($query);
$results = $db->loadObjectList();
// Do what you want with the $results object
Using this means that column names and data values are escaped properly and you've not left with SQL vulnerabilities as #skidr0w mentioned.
Note: #__ is the database table prefix, assuming you've followed this approach. If not, simply replace #__table with the full name of your table
The table column Power is of type float or double. In your first query you try to insert a string value. The second query inserts the correct float by first casting the request value to float and removing the quotes around the value.
By the way, you sould never ever use unfiltered user-input (such as $_GET values) in a sql query.
Actually, after several days I found that the problem and the solution were simpler.
Just removing the '-sign solved the problem
Power='".$_GET["Power"]."'
with
Power=".$_GET["Power"]."
Regards

Concat (2 fields) LIKE submitted value using Propel/Mysql/PHP

Propel/PHP/Mysql question for you. I have a search box that will search names in a table. I need to concat 2 fields, first_name and last_name, and than do a LIKE % submitted string %. All in propel.
This is what I currently have:
$custQuery = CustomerQuery::create()
->withColumn("CONCAT(first_name, ' ', last_name)", "full_name")
->where("full_name LIKE %?%", $nameInput);
This gives the error:
Cannot determine the column to bind to the parameter in clause "full_name = ?".
Obviously I can't use the virtual column in the where statement. When I try to do the concat inside the where statement, I get the same error.
$custQuery = CustomersQuery::create()
->where("CONCAT(first_name, ' ', last_name) LIKE %?%", $searchStr);
I'd prefer to avoid doing this without parameters:
$custQuery = CustomersQuery::create()
->where("CONCAT(first_name, ' ', last_name) LIKE %$searchStr%");
It works, but I am looking for a more propel orientated method of doing this. Is there a way to do this without a where statement at all?
Thanks a ton!
You have to use pseudo column names. So, if your normal filter method for the customers.first_name column is ->filterByFirstName(), then when you use a ->where() or a ->condition() method, you also have to use the "FirstName" pseudo column name instead of 'first_name'.
So, your problem query:
$custQuery = CustomersQuery::create()
->where("CONCAT(first_name, ' ', last_name) LIKE %?%", $searchStr);
would become:
$custQuery = CustomersQuery::create()
->where("CONCAT(Customers.FirstName, ' ', Customers.LastName) LIKE ?", '%'.$searchStr.'%');
I added the table name in there for you too for good measure, and you need to make the percent signs part of the paramater instead of part of the query statement.

PDO params not passed but sprintf is

Unless I am missing something very obvious, I would expect the values of $data1 and $data2 to be the same?? But for some reason when I run this scenario twice (its run once each function call so I'm calling the function twice) it produces different results.
Call 1: PDO = Blank, Sprintf = 3 rows returned
Call 2: PDO = 1 row, Sprintf = 4 rows (which includes the PDO row)
Can someone tell me what I'm missing or why on earth these might return different results?
$sql = "SELECT smacc.account as Smid,sappr.*,CONCAT('$domain/',filepath,new_filename) as Image
FROM `{$dp}table`.`territories` pt
JOIN `{$dp}table`.`approvals` sappr ON pt.approvalID = sappr.ID
JOIN `{$dp}table`.`sm_accounts` smacc ON pt.ID = smacc.posted_territory_id
LEFT JOIN `{$dp}table`.`uploaded_images` upimg ON pt.imageID = upimg.ID
WHERE postID = %s AND countryID = %s AND smacc.account IN (%s) AND languageID = %s";
echo sprintf($sql,$postID,$countryID,implode(',',$accs),$langID);
$qry1 = $db->prepare(str_replace('%s','?',$sql));
$qry1->execute(array($postID,$countryID,implode(',',$accs),$langID));
$data1 = $qry1->fetchAll();
print'<pre><h1>PDO</h1>';print_r($data1);print'</pre>';
$qry2 = $db->query(sprintf($sql,$postID,$countryID,implode(',',$accs),$langID));
$data2 = $qry2->fetchAll();
print'<pre><h1>Sprintf</h1>';print_r($data2);print'</pre><hr />';
The root of the problem is the implode(',',$accs) function.
While you are using sprintf() it will generate a coma separated list and that list will be injected into the query string.
The result will be something like this:
smacc.account IN (1,2,3,4,5)
When you are binding the same list with PDO, it handles it as one value (a string: '1,2,3,4,5'). The "result" will be something like this:
smacc.account IN ('1,2,3,4,5')
Note the apostrophes! -> The queries are not identical.
In short, when you are using PDO and binding parameters, you have to bind each value individually (you can not pass lists as a string).
You can generate the query based on the input array like this:
$query = ... 'IN (?' . str_repeat(', ?', count($accs)-1) . ')' ...
// or
$query = ... 'IN (' . substr(str_repeat('?,', count($accs)), 0, -1) . ')'
This will add a bindable parameter position for each input value in the array. Now you can bind the parameters individually.
$params = array_merge(array($postID, $countryID), $accs, array($langID));
$qry1->execute($params);
Yes as Kris has mentioned the issue with this is the IN part of the query. Example 5 on the following link helps fix this: http://php.net/manual/en/pdostatement.execute.php. I tried using bindParam() but that didn't seem to work so will use Example 5 instead.

How to run a LIKE %..% query using RedBean

I would like to run a query at Redbean.
The query is the following one
"SELECT * FROM tablename WHERE name LIKE "%querystring%" OR
description LIKE "%querystring%"
I tried the following one
$querystring = "querystring";
R::findOne( 'SELECT * FROM tablename WHERE name LIKE ? OR description
LIKE ?', "%$querystring%");
However, this did not work, resulting in error 'Identifier does not conform to RedBeanPHP security policies'.
Another thing I tried was based on this:
R::getAll( 'SELECT * FROM table WHERE title LIKE %:title%',
[':title' => 'home']
);
That gave a RedBean error 'undefined offset: 0'
I'm trying to find a way to do this using prepared statements, so I don't want to construct the query as a string and send it to the server later.
The syntax you need is following:
$mySearchString = "es";
$bean = R::find('bean',' name LIKE :name ',
array(':name' => '%' . $mySearchString . '%' )
);
So as you see the LIKE is written without the wildcards in the sql statement, because that is part of the searchValue. Your first try was quite there, yet the problem was that you've written the php variable inside the quotes thus it didn't resolve.
Also findOne/find are the ORM features of RedBean which are not working with pure SQL strings. Take a closer look on the docs. If you need pure sql try R:getAll like you did. Same example with that one here
$mySearchString = "es";
$bean = R::getAll('SELECT * FROM bean WHERE name LIKE :name ',
array(':name' => '%'.$mySearchString.'%' )
);
foreach($bean as $entry) {
echo $entry['name'] . "<br />";
}
try that
SELECT * FROM tablename WHERE name LIKE '%$querystring%'
OR description LIKE '%$querystring%'
may be you can use like:
"%".$querystring."%"

MySql : can i query " WHERE '$str' LIKE %table.col% "?

Basically i want to add wildcards to the the col value when searching...
Usually I do this the other way around like this:
WHERE cakes.cake_name LIKE '%$cake_search%'
however now i want it to match the inverse:
the user searches for 'treacle
sponge', i want this to match a row
where the cake_name column =
'sponge'.
is this possible?
WHERE '$cake_search' LIKE concat('%',cakes.cake_name, '%')
should work. It will need a full table scan but so will the inverse query. Have you looked into full text search for MySQL? It will likely make this sort of query more efficient.
Why not using MATCH?
MATCH(`cake_name`) AGAINST ('treacle sponge')
You would have to split the user supplied input on the space character and dynamically construct your query to check the column for those values:
$input = "treacle sponge";
$input_words = explode(' ', $input);
$sql_where = "WHERE cakes.cake_name IN('" . implode("','", $input_words) . "')"; // generates: WHERE cakes.cake_name IN('treacle','sponge')
In order to prevent SQL-Injection, I suggest using prepared statements.
$prepStmt = $conn->prepare('SELECT ... WHERE cakes.cake_name LIKE :cake_search
');
if($prepStmt->execute(array('cake_search'=>"%$cake_search%"))) {
...
}
Or, using full text search:
$prepStmt = $conn->prepare('SELECT ... WHERE MATCH (`cake_name`) AGAINST (:cake_search IN BOOLEAN MODE)');
if($prepStmt->execute(array('cake_search'=>$cake_search_words))) {
...
}
See JSON specialchars JSON php 5.2.13 for a complete example.. ;)

Categories