Eval Purpose | SQL transormation? - php

I store my sql queries as strings and then use them later in PDO as shown below.
There is one line that I don't understand:
eval("\$query = \"$query\";");
From the docs..eval should run a string as PHP code. Why can't I just use $query directly? What does it mean to run a string of SQL?
This code works. I just don't know what eval() statement is for.
Note this is safe eval() as the input is not user defined.
"arc_id" => "SELECT id FROM credentials WHERE email=?",
"arc_id_from_hash" => "SELECT id FROM credentials WHERE pass=?",
"signin_pass" => "SELECT pass FROM credentials WHERE email=?",
"signin_validate" => "SELECT id, hash FROM credentials WHERE email=? AND pass=?"
);
public function __construct()
{
$this->db_one = parent::get();
}
public function _pdoQuery($fetchType, $queryType, $parameterArray=0) // needs review
{
$query=$this->sql_array[$queryType];
// what?
eval("\$query = \"$query\";");
// if not input parameters, no need to prep
if($parameterArray==0)
{
$pdoStatement = $this->db_one->query($query);

That code looks up the query by name, e.g. arch_id -> 'SELECT id ..', and then evaluates the query under a double-quote context in eval.
Presumable the queries could contain variables which would be interpolated. For instance, the original value might be 'SELECT id WHERE food = "$taste"' which would then then be evaluated as a double-quoted string literal in the eval and result in the interpolation of $taste so the result stored back in $query might then be 'SELECT id WHERE food = "yucky"'.
Given the data it appears to be "too clever" junk left over from a previous developer. Get rid of it. (If something similar is required in the future, although I would recommend strictly using placeholders, consider non-eval alternative mechanisms.)

eval("\$query = \"$query\";");
This is a variable replacer/templating engine.
It is replacing variables inside $query with their values.
I suggest not using eval for this, it'd probably be better to use preg_replace or str_replace.
For reference, here's a question I asked: PHP eval $a="$a"?

Related

Zend 2 - DB - Escape value without quoting it

I'm looking for a clean way to escape value for SQL query without quoting it.
Let's say i have a value It's cool. Now I would like to simply get escaped string It\'s cool, just like when using for example mysqli_real_escape_string() function for mysqli driver.
The problem is that all Zend\Db\Adapter\Platform interface's quoting methods adds single quotes to the value which means I get 'It\s cool'.
Simplest way I found to do this is to trim quotes after usage of quoteValue() method.
$raw = "It's cool";
$quoted = $this->db->platform->quoteValue($raw);
$final = trim($quoted, "'");
But it's of course a dirty solution and I don't want it to be like this in every place I need escaped-only value.
Is there any clean way to do this simple thing in Zend2?
Maybe you can try something like this:
$sql = "UPDATE posts set comment = :value where id = :id";
$data = ['value' => "It's cool", 'id' => 123];
$stmt= $this->tableGateway->getAdapter()->createStatement($sql);
$stmt->prepare($sql);
$stmt->execute($data);

How to run this mysql query

I am trying to load all records from the database that have been created by the current logged on user in Joomla, im not sure if its possible to have php inside a mysql query though ?, if not how would I go about doing this otherwise ?
SELECT
leadname,
businessname,
postcode,
gasoiluser,
dervuser,
kerouser,
cf_uid,
cf_id
FROM
#__chronoforms_data_addupdatelead
WHERE createdby = '<?php
$user =& JFactory::getUser(); echo $user->get('name') ; ?>'
ORDER BY cf_created DESC
Of course you can access PHP variables for creating the query - as the #__ prefix suggests, you're already running your query from "inside Joomla". Which means it is in php, and something like this should do what you want:
$user =& JFactory::getUser();
$db =& JFactory::getDBO();
if (!$user->guest) {
$query = 'SELECT leadname, businessname, postcode, gasoiluser, '.
' dervuser, kerouser, cf_uid, cf_id '.
' FROM #__chronoforms_data_addupdatelead '.
' WHERE createdby = '.$db->Quote($user->name)).
' ORDER BY cf_created DESC';
$db->setQuery($query);
}
But a little more context would help us see what you'll have to do exactly - what's the code around the SQL query - is it in a php file?
Remember, echo prints to the Response, which is not what you want to do in this case, you want to change the query; so just concatenate the variable content to your query, as shown above; and you should actually be already be in php mode where this query is defined, so the <?php tag is of no use (but again, too few context to be sure about this)!
mysql is a database server that accepts a string and returns either result set or an error
string passed to mysql must be proper SQL statement
what you have in your question is not proper SQL statement, it is a string waiting to be parsed by PHP and whoever knows by who else
this part is PHP for sure:
<?php $user =& JFactory::getUser(); echo $user->get('name') ; ?>
this part is something like a placeholder for correct table name that is replaced at runtime of whatever you got this query from(supposedly joomla):
#__chronoforms_data_addupdatelead
if you want to run that query you must to figure out what to substitute with the aforementioned blocks

Does this work to stop sql injections

I have been using the block of code below to supposedly stop sql injections. It is something someone showed me when I first started php(which was not that long ago)
I place it in every page just as shown on the open. I am wondering if it is effective? I do not know how to test for sql injections
<?php
//Start the session
session_start();
//=======================open connection
include ('lib/dbconfig.php');
//===============This stops SQL Injection in POST vars
foreach ($_POST as $key => $value) {
$_POST[$key] = mysql_real_escape_string($value);
}
foreach ($_GET as $key => $value) {
$_GET[$key] = mysql_real_escape_string($value);
}
My typical insert and update queries look like this
$insert = ("'$email','$pw','$company', '$co_description', '$categroy', '$url', '$street', '$suite', '$city', '$state', '$zip', '$phone', '$date', '$actkey'");
mysql_query("INSERT INTO provider (email, pw, company, co_description, category, url, street, suite, city, state, zip, phone, regdate, actkey) VALUES ($insert)") or die ('error ' . mysql_error());
mysql_query("UPDATE coupon SET head='$_POST[head]', fineprint='$_POST[fineprint]', exdate='$exdate', creationdate=NOW() WHERE id='$cid'") or die ('error ' . mysql_error());
That's somewhat effective, but it's suboptimal -- not all of the data you receive in _GET and _POST will go into the database. Sometimes you might want to display it on the page instead, in which case mysql_real_escape_string can only hurt (instead, you'd want htmlentities).
My rule of thumb is to only escape something immediately before putting it into the context in which it needs to be escaped.
In this context, you'd be better of just using parameterized queries -- then escaping is done for you automatically.
This is not enough.
1. You're missing cookies, $_COOKIE variable.
2. If you use $_REQUEST you're in trouble.
3. You didn't show your queries, you must enquote each variable with single quotes '' when you put it into query (especiall when the data is supposted to be an integer and you might think that quote is not necessary in that case, but that would be a big mistake).
4. Data used in your query could come from other source.
The best way is to use data binding and have the data escaped automatically by the driver, this is available in PDO extension.
Example code:
$PDO = new PDO('mysql:dbname=testdb;host=127.0.0.1' $user, $password);
$stmt = $PDO->prepare("SELECT * FROM test WHERE id=? AND cat=?");
$stmt->execute(array($_GET["id"], $_GET["cat"]));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
You can also bind data using string keys:
$stmt = $PDO->prepare("SELECT * FROM test WHERE id = :id AND cat = :cat");
$stmt->execute(array(":id" => $_GET["id"], ":cat" => $_GET["cat"]));
If you want to learn PDO, you might find useful these helper functions I use:
http://www.gosu.pl/var/PDO.txt
PDO_Connect(dsn, user, passwd) - connects and sets error handling.
PDO_Execute(query [, params]) - only execute query, do not fetch any data.
PDO_InsertId() - last insert id.
PDO_FetchOne(query [, params]) - fetch 1 value, $count = PDO_FetchOne("SELECT COUNT(*) ..");
PDO_FetchRow(query [, params]) - fetch 1 row.
PDO_FetchAll(query [, params]) - fetch all rows.
PDO_FetchAssoc(query [, params]) - returns an associative array, when you need 1 or 2 cols
1) $names = PDO_FetchAssoc("SELECT name FROM table");
the returned array is: array(name, name, ...)
2) $assoc = PDO_FetchAssoc("SELECT id, name FROM table")
the returned array is: array(id=> name, id=>name, ...)
3) $assoc = PDO_FetchAssoc("SELECT id, name, other FROM table");
the returned array is: array(id=> array(id=>'',name=>'',other=>''), id=>array(..), ..)
Each of functions that fetch data accept as 2nd argument parameters array (which is optional), used for automatic data binding against sql injections. Use of it has been presented earlier in this post.
Kind of.
The mysql_real_escape_string function takes the given variable and escapes it for SQL queries. So you can safely append the string into a query like
$safe = mysql_real_escape_string($unsafe_string);
$query = 'SELECT * FROM MyTable WHERE Name LIKE "' . $safe . '" LIMIT 1';
It does NOT protect you against someone putting malicious code into that query to be displayed later (i.e. XSS or similar attack). So if someone sets a variable to be
// $unsafe_string = '<script src="http://dangerous.org/script.js"></script>'
$safe = mysql_real_escape_string($unsafe_string);
$query = 'UPDATE MyTable SET Name = "' . $safe . '"';
That query will execute as you expect, but now on any page where you print this guy's name, his script will execute.
This is completely WRONG approach.
In fact, you are mimicking infamous magic quotes, which is acknowledged as a bad practice. With all it's faults and dangers.
To help you understand why your initial way was wrong Magic quotes in PHP
To help you understand why escaping has nothing to do with "data safety" yet not sufficient to protect your query: Replacing mysql_* functions with PDO and prepared statements
To help you understand when prepared statements not sufficient either and what to do in these cases: In PHP when submitting strings to the database should I take care of illegal characters using htmlspecialchars() or use a regular expression?
this is not to prevent SQL Injection the real escape method only add \ to the dangerous
characters like " or ' so a string with "hi"do'like" will become "hi\"do\'like\" so it is
less dangerous
this method is not always usefull ; in case you want to display the content of tha escaped
variable in a page it will only destroy it and make it less readable

SQL full text search with PHP and PDO

I'm trying to write a simple, full text search with PHP and PDO. I'm not quite sure what the best method is to search a DB via SQL and PDO. I found this this script, but it's old MySQL extension. I wrote this function witch should count the search matches, but the SQL is not working. The incoming search string look like this: 23+more+people
function checkSearchResult ($searchterm) {
//globals
global $lang; global $dbh_pdo; global $db_prefix;
$searchterm = trim($searchterm);
$searchterm = explode('+', $searchterm);
foreach ($searchterm as $value) {
$sql = "SELECT COUNT(*), MATCH (article_title_".$lang.", article_text_".$lang.") AGINST (':queryString') AS score FROM ".$db_prefix."_base WHERE MATCH (article_title_".$lang.", article_text_".$lang.") AGAINST ('+:queryString')";
$sth = $dbh_pdo->prepare($sql);
$sql_data = array('queryString' => $value);
$sth->execute($sql_data);
echo $sth->queryString;
$row = $sth->fetchColumn();
if ($row < 1) {
$sql = "SELECT * FROM article_title_".$lang." LIKE :queryString OR aricle_text_".$lang." LIKE :queryString";
$sth = $dbh_pdo->prepare($sql);
$sql_data = array('queryString' => $value);
$sth->execute($sql_data);
$row = $sth->fetchColumn();
}
}
//$row stays empty - no idea what is wrong
if ($row > 1) {
return true;
}
else {
return false;
}
}
When you prepare the $sql_data array, you need to prefix the parameter name with a colon:
array('queryString' => $value);
should be:
array(':queryString' => $value);
In your first SELECT, you have AGINST instead of AGAINST.
Your second SELECT appears to be missing a table name after FROM, and a WHERE clause. The LIKE parameters are also not correctly formatted. It should be something like:
sql = "SELECT * FROM ".$db_prefix."_base WHERE article_title_".$lang." LIKE '%:queryString%' OR aricle_text_".$lang." LIKE '%:queryString%'";
Update 1 >>
For both SELECT statements, you need unique identifiers for each parameter, and the LIKE wildcards should be placed in the value, not the statement. So your second statement should look like this:
sql = "SELECT * FROM ".$db_prefix."_base WHERE article_title_".$lang." LIKE :queryString OR aricle_text_".$lang." LIKE :queryString2";
Note queryString1 and queryString2, without quotes or % wildcards. You then need to update your array too:
$sql_data = array(':queryString1' => "%$value%", ':queryString2' => "%$value%");
See the Parameters section of PDOStatement->execute for details on using multiple parameters with the same value. Because of this, I tend to use question marks as placeholders, instead of named parameters. I find it simpler and neater, but it's a matter of choice. For example:
sql = "SELECT * FROM ".$db_prefix."_base WHERE article_title_".$lang." LIKE ? OR aricle_text_".$lang." LIKE ?";
$sql_data = array("%$value%", "%$value%");
<< End of Update 1
I'm not sure what the second SELECT is for, as I would have thought that if the first SELECT didn't find the query value, the second wouldn't find it either. But I've not done much with MySQL full text searches, so I might be missing something.
Anyway, you really need to check the SQL, and any errors, carefully. You can get error information by printing the results of PDOStatement->errorCode:
$sth->execute($sql_data);
$arr = $sth->errorInfo();
print_r($arr);
Update 2 >>
Another point worth mentioning: make sure that when you interpolate variables into your SQL statement, that you only use trusted data. That is, don't allow user supplied data to be used for table or column names. It's great that you are using prepared statements, but these only protect parameters, not SQL keywords, table names and column names. So:
"SELECT * FROM ".$db_prefix."_base"
...is using a variable as part of the table name. Make very sure that this variable contains trusted data. If it comes from user input, check it against a whitelist first.
<< End of Update 1
You should read the MySQL Full-Text Search Functions, and the String Comparison Functions. You need to learn how to construct basic SQL statements, or else writing even a simple search engine will prove extremely difficult.
There are plenty of PDO examples on the PHP site too. You could start with the documentation for PDOStatement->execute, which contains some examples of how to use the function.
If you have access to the MySQL CLI, or even PHPMyAdmin, you can try out your SQL without all the PHP confusing things. If you are going to be doing any database development work as part of your PHP application, you will find being able to test SQL independently of PHP a great help.

mysql IN parameter

When the user check more than one (checkbox) option which are then combine into a string of "apple,orange,pear"
SELECT id, pos, FROM $db WHERE dtime>='$now' AND jsub IN ('$arr[1]') ;
When I pass the string to $arr[1], it won't work correctly, how do I split into array and get mysql IN function to process correctly?
use:
$str = "SELECT id, pos, FROM $db
WHERE dtime>='$now' AND jsub IN ('".explode(',',$arr."')";
and don't forget to sanitize the parameters before ...
Use FIND_IN_SET.
SELECT id, pos, FROM $db WHERE dtime>='$now' AND FIND_IN_SET(jsub, '$arr[1]')
the question is WAY unclear, but I suspect you want something like
foreach ($arr as $key => $item) $arr[$key] = mysql_real_escape_string($item);
$in = "'".implode("','",$arr);
$sql = "SELECT id, pos, FROM $db WHERE dtime>='$now' AND jsub IN ($in)";
But man, I hate guessing.
Why don't you get yourself a static query, without any PHP code?
To see, if it ever works?
If not - ask on SO for the proper query. SQL query, not PHP code.
If yes - write a PHP code that produces the exact query.
Compare to the example one.
If failed - ask on SO for the PHP code, providing an example of the resulting query and an array.
Is it too hard rules to follow?

Categories