I'm a newbie to mysql, I managed to scrape this together to get the result I wanted. Can it be coded better? Are there any security risks? Its being output in php.
$qwe = $product->virtuemart_product_id;
$id = mysql_real_escape_string($qwe);
$result = mysql_query('SELECT * FROM virtuemart_product_medias where virtuemart_product_id = ' . $id . ' LIMIT 1');
$row = mysql_fetch_assoc($result);
$matched = $row['virtuemart_media_id'];
$result2 = mysql_query('SELECT * FROM virtuemart_medias where virtuemart_media_id = ' . $matched . ' LIMIT 1');
$row2 = mysql_fetch_assoc($result2);
$matched2 = $row2['file_url_thumb'];
echo $matched2;
I don't know whether or not there is a security hole in the specific code you provided - that depends on what other validation exists elsewhere in your program, and what you consider to be a security hole. But the way you are coding means that there definitely could be security holes. Let's look at your first query:
$id = mysql_real_escape_string($qwe);
$result = mysql_query('SELECT *
FROM virtuemart_product_medias
WHERE virtuemart_product_id = ' . $id . ' LIMIT 1');
Imagine if $qwe is the string 0 OR 1=1 --. The mysql_real_escape_string only escapes certain characters such as quotes and backslashes.
mysql_real_escape_string() calls MySQL's library function mysql_real_escape_string, which prepends backslashes to the following characters: \x00, \n, \r, \\, ', " and \x1a.
The string 0 OR 1=1 -- that I mentioned above does not contain any of these characters so it will not be affected at all by mysql_real_escape_string. After you substitute in the value of $id, the resulting SQL query will look something like this:
SELECT *
FROM virtuemart_product_medias
WHERE virtuemart_product_id = 0 OR 1=1 -- LIMIT 1
As you can see, this will return all rows.
Long story short: Use PDO and parameterized queries.
Related
How can I prevent SQL injection in PHP?
Firstly, never use the mysql_* functions. They are deprecated and relying on them is highly discouraged. Use either MySQLi or PDO
The above query could be rewritten as
SELECT file_url_thumb FROM virtuemart_medias where virtuemart_media_id = (SELECT virtuemart_media_id FROM virtuemart_product_medias where virtuemart_product_id = ' . $id . ' LIMIT 1) LIMIT 1
Never do a SELECT *. Include only those fields in your query which you need in your code.
Use one query instead of two, and select only the fields you're using, like so:
SELECT `file_url_thumb` FROM virtuemart_medias where virtuemart_media_id = (SELECT `virtuemart_media_id` FROM virtuemart_product_medias where virtuemart_product_id = ' . $id . ' LIMIT 1) LIMIT 1
You can always use a join;
SELECT a.virtuemart_media_id, b.file_url_thumb
FROM virtuemart_product_medias a
LEFT JOIN virtuemart_medias b
ON a.virtuemart_media_id = b.virtuemart_media_id
WHERE virtuemart_product_id = $id
LIMIT 1
That'll always get you the virtuemart_media_id and, if it exists file_url_thumb.
Your query has a problem also, mysql_real_escape_string only escapes strings, since you're not quoting the $id in the query, it won't be handled as a string and the escaping will not help you. As other replies point out, you should really be using mysqli or PDO.
How about this:
SELECT a.file_url_thumb
FROM virtuemart_medias a
LEFT JOIN virtuemart_product_medias b on a.virtuemart_media_id=b.irtuemart_media_id
WHERE a.virtuemart_product_id=' . $id . ' LIMIT 1
Related
I need to write this query with Doctrine. How can I write it down using QueryBuilder?
SELECT charges.id, charges.currency, charges.total_transactions,
charges.total_volume, charges.commission, refunds.total_payouts
FROM
(SELECT ...very long query...) charges
LEFT JOIN
(SELECT ...very long query...) refunds
ON charges.id = refunds.id AND charges.currency = refunds.currency
You can use Native SQL and map results to entities:
use Doctrine\ORM\Query\ResultSetMapping;
$rsm = new ResultSetMapping;
$rsm->addEntityResult('AppBundle:Charges', 'charges')
->addEntityResult('AppBundle:Refunds', 'refunds')
->addFieldResult('charges', 'id', 'id')
->addFieldResult('charges', 'currency', 'currency')
->addFieldResult('charges', 'total_transactions', 'total_transactions')
->addFieldResult('charges', 'total_volume', 'total_volume')
->addFieldResult('charges', 'commission', 'commission')
->addFieldResult('refunds', 'total_payouts', 'total_payouts')
;
$sql = "
SELECT
charges.id,
charges.currency,
charges.total_transactions,
charges.total_volume,
charges.commission,
refunds.total_payouts
FROM
(SELECT ...very long query...) charges
LEFT JOIN
(SELECT ...very long query...) refunds ON charges.id = refunds.id AND charges.currency = refunds.currency
WHERE some_field = ?
";
$query = $this->getEntityManager()->createNativeQuery($sql, $rsm);
$query->setParameter(1, $name);
$entities = $query->getResult();
You can use DQL like this:
$dql = "SELECT ...";
$q = $entityManager->createQuery($dql)->setParameters($arrayParameters);
$result = $q->execute();
or QueryBuilder for each sub-query, like:
// subquery 1
$subQuery1 = $entityManager->createQueryBuilder()
->select('...')
->from('...')
->getDQL()
;
// subquery 2
$subQuery2 = ...
// etc
// ...
// main query
$query = $entityManager->createQueryBuilder()
->select('...')
->from('...', $subQuery1)
->leftJoin('...', $subQuery1->getDQL()),
->where()
;
PS: I just try provide gist for you... hope now you have clue...
Now I found out that it's impossible.
Comment created by stof:
DQL is about querying objects. Supporting subselects in the FROM clause means that the DQL parser is not able to build the result set mapping anymore (as the fields returned by the subquery may not match the object anymore).
This is why it cannot be supported (supporting it only for the case you run the query without the hydration is a no-go IMO as it would mean that the query parsing needs to be dependant of the execution mode).
In your case, the best solution is probably to run a SQL query instead (as you are getting a scalar, you don't need the ORM hydration anyway)
Source: https://github.com/doctrine/doctrine2/issues/3542
I have drop down where the drop down is list of namaJabatan
my table - infojawatan
ID - PK of the table
namaJabatan - where the condition appear ($search - its up to where the user select from Dropdown)
tarikhKemaskini - where i want to get the latest date of row
my query
$sql = "SELECT * FROM infojawatan WHERE namaJabatan = '$search' && tarikh Kemaskini IN (SELECT MAX(tarikhKemaskini) FROM infojawatan GROUP BY ID)";
$sql_rs = mysql_query($sql);
while($row_Sql = mysql_fetch_array($sql_rs)) {
$tarikhKemaskini = $row_Sql['tarikhKemaskini'];
}
echo "Current Date :" .$tarikhKemaskini;
You have a few syntax errors in your SQL.
SQL spells out AND, not &&.
tarikhKemaskini is one word.
SELECT *
FROM infojawatan
WHERE namaJabatan = :namaJabatan AND
tarikhKemaskini IN (
SELECT MAX(tarikhKemaskini)
FROM infojawatan
GROUP BY ID
)
Note carefully that I used :namaJabatan there instead of hard coding $search. Hard coding variables into SQL leaves you open to a SQL Injection Attack where a malicious attacker can craft a search query that lets them get more information than they're allowed to, or even run arbitrary SQL queries.
Instead, use parameters, the :namaJabatan there, and pass your variables in when you execute the query.
Unfortunately the mysql_query interface doesn't support this. Fortunately it was deprecated and there are now better interfaces. Here's a breakdown. I'd recommend using PDO as it is a generic interface applicable to any SQL database. Then you can use the more secure and efficient prepared statements with bind parameters.
$stmt = $dbh->prepare("
SELECT *
FROM infojawatan
WHERE namaJabatan = :namaJabatan AND
tarikhKemaskini IN (
SELECT MAX(tarikhKemaskini)
FROM infojawatan
GROUP BY ID
)
")
$stmt->execute(array( ':namaJabatan' => $search));
while( $row = $stmt->fetch() ) {
echo $row['tarikhKemaskini'];
}
I have a sequence of ids that merged by a comma :
$ids = '1,2,3,4,5,6,7,8,9,10' ;
select * from ads WHERE id = $ids ...
now how can I get content of ads table by these ids ?
You are using PHP. You can build the SQL like this:
$ids = '1,2,3,4,5,6,7,8,9,10';
$sql = 'SELECT * FROM ads WHERE id IN ('.$ids.')';
//execute the query (don't use mysql_* function ;) )
Since MySQL 5.6 you can use FIND_IN_SET() too:
$ids = '1,2,3,4,5,6,7,8,9,10';
$sql = "SELECT * FROM ads WHERE FIND_IN_SET(id, '".$ids."')";
//execute the query (don't use mysql_* function ;) )
Use IN operator
Try this:
SELECT *
FROM ads
WHERE id IN ($ids);
I have this mysql query:
SELECT
freeAnswers.*,
(SELECT `districtCode`
FROM `geodatas`
WHERE `zipCode` = clients.zipCode
GROUP BY `zipCode`
LIMIT 0, 1) as districtCode,
clients.zipCode,
clients.gender,
clients.startAge,
clients.endAge,
clients.mail,
clients.facebook,
surveys.customerId,
surveys.activityId,
surveys.name as surveyName,
customers.companyName,
activities.name as activityName
FROM freeAnswers,
clients,
surveys,
customers,
activities
WHERE freeAnswers.surveyId = surveys.id
AND surveys.customerId = customers.id
AND activities.id = surveys.activityId
AND clients.id = freeAnswers.clientId
AND customers.id = 1
ORDER BY activityName asc
LIMIT 0, 10
the query is correct on my mysql server but when I try to use it in Zend Framework 1.11 model
I get this error: Mysqli prepare error: Operand should contain 1 column(s)
Please, could anyone help me to make it run well?
Best Regards,
Elaidon
Here is some code that should work. Zend_Db_Select doesn't really provide a way to select from multiple tables in the FROM clause without using a JOIN so this feels a bit hackish to me in regards to one small part of the query. Your best bet will probably be to rewrite the query using JOINs where appropriate.
$subselect = $db->select()
->from('geodatas', 'districtCode')
->where('zipCode = clients.zipCode')
->group('zipCode')
->limit(1, 0);
$from = $db->quoteIdentifier('freeAnswers') . ', ' .
$db->quoteIdentifier('clients') . ', ' .
$db->quoteIdentifier('surveys') . ', ' .
$db->quoteIdentifier('customers') . ', ' .
$db->quoteIdentifier('activities');
$select = $db->select()
->from(array('activities' => new Zend_Db_Expr($from)),
array('freeanswers.*',
'districtCode' =>
new Zend_Db_Expr('(' . $subselect . ')'),
'clients.zipCode', 'clients.gender', 'clients.startAge',
'clients.endAge', 'clients.mail', 'clients.facebook',
'clients.customerId', 'clients.activityId',
'surveyName' => 'surveys.name', 'customers.companyName',
'activityName' => 'activities.name'))
->where('freeAnswers.surveyId = surveys.id')
->where('surveys.customerId = customers.id')
->where('activities.id = surveys.activityId')
->where('clients.id = freeAnswers.clientId')
->where('customers.id = ?', 1)
->order('activityName ASC')
->limit(10, 0);
The only reason I say it is hackish is because of the line:
->from(array('activities' => new Zend_Db_Expr($from)),
Since from() really only works with one table, I create a Zend_Db_Expr and specify the correlation as the last table name in the expression. If you don't pass a Zend_Db_Expr, it will either quote your comma separated table name incorrectly, or if you pass an array of table names, it just uses the first. When you pass a Zend_Db_Expr with no name, it defaults to use AS t which also doesn't work in your case. That is why I put it as is.
That returns the exact SQL you provided except for the last thing mentioned. Here is actually what it returns:
SELECT
`freeanswers`.*,
(SELECT `geodatas`.`districtCode`
FROM `geodatas`
WHERE (zipCode = clients.zipCode)
GROUP BY `zipCode`
LIMIT 1) AS `districtCode`,
`clients`.`zipCode`,
`clients`.`gender`,
`clients`.`startAge`,
`clients`.`endAge`,
`clients`.`mail`,
`clients`.`facebook`,
`clients`.`customerId`,
`clients`.`activityId`,
`surveys`.`name` AS `surveyName`,
`customers`.`companyName`,
`activities`.`name` AS `activityName`
FROM `freeAnswers`,
`clients`,
`surveys`,
`customers`,
`activities` AS `activities`
WHERE (freeAnswers.surveyId = surveys.id)
AND (surveys.customerId = customers.id)
AND (activities.id = surveys.activityId)
AND (clients.id = freeAnswers.clientId)
AND (customers.id = 1)
ORDER BY `activityName` ASC
LIMIT 10
So that will work but eventually you will want to rewrite it using JOIN instead of specifying most of the WHERE clauses.
When dealing with subqueries and Zend_Db_Select, I find it easy to write each subquery as their own queries before writing the final query, and just insert the subqueries where they need to go and Zend_Db handles the rest.
Hope that helps.
I am creating a function to get all keywords from a database
The database has two tables
keywords [id | word | account] ( aliased as k )
keywordsTemplateLink [templateId | keywordId] ( aliased as ktl )
the functions signature is
getKeywords($id = null){}
so the way it works is,
if id != null a where clause is added which must limit the result set to keywords where ktl.templateId = $id
What would be the most effective way to achieve this query?
Im thinking SELECT id, keyword FROM keywords k, templatekeywordlink tkl WHERE tkl.templateId= $id AND tkl.keywordId = k.id AND k.account=$account
Is there a better way?
function getKeywords($id = null){
//query generated by function
$query .= ($id != null) ? ' where ktl.templateId = ' . $id : '';
}
It is generally bad practice to create sql by variable concatenation in this way..
If you don't want some script kiddie to pwn you via sql injection, use prepared queries.
$stm = $dbo->prepare("SELECT id, keyword FROM keywords k, templatekeywordlink tkl WHERE tkl.templateId= ? AND k.account=?);
$stm->execute(array($id,$account));