MySQL to Drupal 7 db_select - mysql

I am trying to execute the following mysql query below with drupal 7 db_select. But I cant understand how this can be done. Is anyone can help me to translate the following mysql query into drupal 7 dynamic db query?
My main goal is actually sorting the mysql result by given string position in the name. Please keep in mind that i dont want to fetch all the results and sort them with php, instead I want to use mysql to do that. As i know the "ORDER BY LOCATE" command is doing that exactly.
SELECT name FROM `taxonomy_term_data` WHERE LOCATE('credit', name) > 0 ORDER BY LOCATE('credit', name)

1. Proper example of db_select
It is possible, using drupal 7 db_select, here is my example working code (done with help of this post)
My example in with table cities containing column city. Find cities with double "o" and sort by it's position:
$r = db_select('cities', 't')
->fields('t')
->condition('t.city', '%' . db_like('oo') . '%', 'LIKE');
$r->addExpression("LOCATE('oo', city) ", 'loc');
$r = $r->orderBy('loc', 'DESC')
->execute()
->fetchAllAssoc("id");
So similar in your example would be:
$r = db_select('taxonomy_term_data', 't')
->fields('t')
->condition('t.name', '%' . db_like('credit') . '%', 'LIKE');
$r->addExpression("LOCATE('credit', name) ", 'loc');
$r = $r->orderBy('loc', 'DESC'); //Or ASC
//Execute your query and gather result anyway you want.
2. Do you need to use db_select?
As someone stated in comment in link I posted "There are times and places to just use db_query."
I think this is that time :) Dont overcomplicate your code just to use drupal-way logic, which is often outdated or just too simple for complex tasks.

I think you should try something like this. db_like function seems to do what you are looking for.
$result = db_select('taxonomy_term_data', 'ttd')
->fields('ttd', 'name')
->condition('ttd.name, '%' . db_like('credit') . '%', 'LIKE')
->orderBy('ttd.name', 'DESC')
->execute();

Related

Simple Select Query taking too much time in mysql-table with large data-set 10M

SELECT *
FROM many_leads_lead_details
WHERE location LIKE '%Los%Angeles%'
AND (keywords LIKE '%Real%' or
keywords LIKE '%Real Estate%' or
keywords LIKE '%Real Estate Agent%')
above query is taking too much time as compared to localhost database.
the database taking time is hosted on another server,
response time as below
Localhost = 30.00 Seconds
and on
rds.amazonaws.com = 1.50 Minuts
$leads2 = LeadDetails::query();
$temp = '';
$location = str_replace(' ', '%', explode(',', $campaign->location)[0]);
$leads2->Where('location', 'like', '%' . $location . '%');
//dd($leads2->get());
$leads2->Where(function ($query) use ($campaign, $temp) {
foreach (explode(' ', $campaign->keywords) as $index => $keyword) {
if ($index == 0) {
$temp .= $keyword;
} else {
$temp .= ' ' . $keyword;
}
$query->OrWhere('keywords', 'like', '%' . $temp . '%');
}
});
$leads2->get();
This query:
SELECT *
FROM many_leads_lead_details
WHERE location LIKE '%Los%Angeles%'
AND (keywords LIKE '%Real%' or
keywords LIKE '%Real Estate%' or
keywords LIKE '%Real Estate Agent%')
requires a full table scan. Indexes cannot be used because of the wildcards at the beginning of the LIKE patterns.
My first suggestion is to fix your data model. I suspect you are storing multiple values in keywords. These should be in a separate table.
The second suggestion is to use full text search -- the match() function. That is too long a topic for an answer here. You should start with the documentation.
WHERE location LIKE '%Los%Angeles%'
AND (keywords LIKE '%Real%' or
keywords LIKE '%Real Estate%' or
keywords LIKE '%Real Estate Agent%')
-->
WHERE MATCH(location, keywords) AGAINST ('Los Angeles Real Estate Agent')
and have
FULLTEXT(location, keywords)
This will run a lot faster.
You have mentioned that the local database returns results quicker. Assuming both databases have similar or same amount of data.
Check if you have indexes the same indexes in both servers.
If there are no difference in indexes, there is a possibility that the remote server is using different query plan. If you find the issue is table scan, you can try to introduce rowcount and pagecount to performance tune:
UPDATE STATISTICS [many_leads_lead_details] WITH ROWCOUNT = 50000000, PAGECOUNT = 500000
Try the Update stats and rerun the query. Hope this helps.
use DB facade instead of eloquent query when you select multiple records from database and you don't want relationship with the records returned by the query
When selecting records from the database and you don't need table relationship then it is best to use DB facade over eloquent

Get ABS(absolute value) in laravel Query

I'm new to Laravel framework and I'm looking for how to write Query in order to get the absolute value(in short ignoring the + and - sign and only display number from database.
I know we can use Abs in order to get it. But I don't know how do it.
Take a look at my code:
$users = DB::table('transaction_details')->
Join('ledger','transaction_details.ledger','=','ledger.Name')->
groupBy('ledger.Name')->select(
'ledger.CrDr as CrDr',
'transaction_details.ledger as Name',
'transaction_details.amount as Debit',
'ledger.OpeningBalance as openingBalance'
)->get();
In above query i want ledger.openingBalance value to be absolute.
How do I do that?
You can use DB::raw for the ledger.openingBalance select column to avoid it from being quoted by the Query Builder:
DB::table('transaction_details')
->join('ledger','transaction_details.ledger','=','ledger.Name')
->groupBy('ledger.Name')
->select(
'ledger.CrDr as CrDr',
'transaction_details.ledger as Name',
'transaction_details.amount as Debit',
DB::raw('ABS(ledger.OpeningBalance) as openingBalance')
)->get();

MySQL Select Similar Query Match one by one

Ok... so i made this code:
$resultssimilar = mysql_query($wtf="SELECT * FROM data WHERE `keywords` LIKE '%" . str_replace(',', '%', str_replace(' ', '', $data['keywords'])) . "%'");
while($sim = mysql_fetch_array($resultssimilar)) {
echo '<!--'.$sim['name'].'-->';
}
So i have in $data['keywords'] few keywords: "weather, today, sunday" or "news, important, europe" etc..
If i use the code above, it will fetch only the article with same keywords... So it will only fetch the same article ...
My question is... How can i change the MySQL query in a way which to show really similar articles by one or two words?

MySQL injection penetration

I'm new here so I'll try to make my post as clear and readable as possible.
While browsing some site's log I came across some hacking attempts that I want to recreate/test in a closed server. I made a simple PHP web page that gets a variable named 'id' and without any filtering/validation use it in a query.
Relevant PHP code
$var = $_GET['id'];
echo $_GET['id'] . "<br>\n";
include ( "/var/www/dbconnect.php" );
$mysqli = new mysqli ( $db_host, $db_user, $db_password, "news" );
if ( $mysqli->connect_errno ) { echo "Failed to connect to MySQL: (" . $mysqli- >connect_errno . ") " . $mysqli->connect_error; }
$query = "SELECT id, date, subject FROM news_table WHERE id=" . $var;
//$query = "SELECT id, date, subject FROM news_table WHERE id=250; DROP TABLE test;"; // This won't work because in PHP's implementation multiple statements are not allowed
if ( ! $result = $mysqli->query ( $query ) ) { echo "CALL failed: (" . $mysqli->errno . ") " . $mysqli->error; } else { }
Then I load the page using the following
testserver/test-files/test-mysql-vulnerability.php?id=362099999.1
union select unhex(hex(version())) -- 1=1
and get this result:
CALL failed: (1222) The used SELECT statements have a different number
of columns
The hacker spent 5 minutes sending numerous combinations trying to break into our production server. My production server does not give any indication of success/failure like the error above.
My question is: Can the above hack work when the number of columns don't match? If so how?
tnx
As noted in the comments, don't do this.
To answer your question, though, union is useful in injections because it allows you to use an unrelated table in the output. The error you're seeing is because the original database query wanted a certain number and type of columns, and the injected query wanted only one. In this case we know that we need three columns (from the code), so we want the resultant SQL statement to be
SELECT id, date, subject FROM news_table WHERE id=3 union select 0, 0, unhex(hex(version())) --
(This may not work exactly depending on your data types and my ability to do this off the top of my head).
SELECT id,
date,
subject
FROM news_table
WHERE id = 3
UNION
SELECT NULL AS id,
NULL AS date,
Unhex(Hex(Version())) AS subject
also use mysql instead of mysqli as it is more prone to injections

mysql_real_escape_string ISSUE

If I type
'
into my search bar I get a mysql error as the "sting" has not been escaped- it think.
But the reason why I cant escape it is because I dont think it currently is a string.
the search box generates search results dynamically with ajax it is as I type and it finds the results that I get the error:
You have an error in your SQL syntax; check the manual that corresponds to
your MySQL server version for the right syntax to use near '%' OR Location
LIKE '%'%' OR Map LIKE '%'%' LIMIT 0, 16' at line 2
This is the mysql query:
<?php
if($_POST['q']!=""){
include $_SERVER['DOCUMENT_ROOT'] . "/include/datebasecon.php";
$result = mysql_query("
SELECT id, Name, Location, Map
FROM Accommodation WHERE Name LIKE '%".$_POST['q']."%' OR Location LIKE '%".$_POST['q']."%' OR Map LIKE '%".$_POST['q']."%' LIMIT 0, 16")
or die(mysql_error());
$output = "";
while($row = mysql_fetch_array($result)){
$N = preg_replace("/(".$_POST['q'].")/i","<span>$1</span>",$row['Name']);
$L = preg_replace("/(".$_POST['q'].")/i","<span>$1</span>",$row['Location']);
$M = preg_replace("/(".$_POST['q'].")/i","<span>$1</span>",$row['Map']);
$output .= "<p>".$N." - ".$L."</p>";
}
print $output;
}
?>
Is there anyway i can fix this after its post the query maybe?
When magic_quotes_gpc is off (as it should be!), $_POST['q'] is simply the string ', as just one character. That's why it's appearing in your SQL code like this:
%' OR Location LIKE '%'%' OR Map LIKE '%'%' LIMIT 0, 16
The error takes place at '%'%' because the LIKE string is being prematurely terminated.
You can just use mysql_real_escape_string() on $_POST['q'] and it'll be escaped:
$q = mysql_real_escape_string($_POST['q']);
$result = mysql_query("
SELECT id, Name, Location, Map
FROM Accommodation WHERE Name LIKE '%".$q."%' OR Location LIKE '%".$q."%' OR Map LIKE '%".$q."%' LIMIT 0, 16")
or die(mysql_error());
You wrote "I dont think it currently is a string"... it is a string. You can pass it to mysql_real_escape_string() and use the result to make your query secure and reliable. Everything your script receives by the $_POST, $_GET, $_REQUEST and $_COOKIE params can be used as string, except it is an array.
To make you understand.
Look at your query:
LIKE '%search string%'
note apostrophes you have used to delimit search string.
These apostrophes does mean that data inside IS a string.
Everything you put in quotes into query is a string.
Everything you put in quotes into query must be escaped.
No need to think, consider or estimate. The rule is simple and unambiguous: quoted text should be always escaped.