I kwnow that using an ORM like Doctrine2 for building queries is safe, meaning that parameters are escaped by default.
But i'm guessing that this is not so obvious when using literals and when this literal comes directly from the query string:
$builder = $this->getRepository()->createQueryBuilder('e');
$request = $this->getRequest();
// Loop each allowed filter field and check if exists in $request
foreach($this->getFilterFields() as $filter) :
// Skip falsy values in $request
if(!$value = $request->get($filter)) continue;
// Add OR LIKE %$value% where $value is GET paramter
$like = $builder->expr()->literal("%$value%");
$builder->orWhere($builder->expr()->like("e.$filter", $like));
endforeach;
Should safety be improved in some way?
$queryBuilder->expr returns an ExpressionBuilder object. Inside ExpressionBuilder we find:
public function literal($input, $type = null)
{
return $this->connection->quote($input, $type);
}
So literals do get quoted and should be fine to use.
We also find:
public function like($x, $y)
{
return $this->comparison($x, 'LIKE', $y);
}
public function comparison($x, $operator, $y)
{
return $x . ' ' . $operator . ' ' . $y;
}
$y is fine because it goes through literal first. Do want to be a bit careful about $x. As long as your filterFields are internal then no problem. If they are coming from the user then you need to make sure they are valid.
Related
I changed my mysqli connection to PDO statment so i have to much error on my page this is the my code pls help us
.
.
.
if ($fn && $ln && $e && $p) { // If everything's OK...
// Make sure the email address is available:
//$q = "SELECT user_id FROM users WHERE email='$e'";
$q = $dbc->query("SELECT user_id FROM users WHERE email='$e'");
$q->execute(array($e));
$r = $q->fetchAll(PDO::FETCH_ASSOC);
//$r = mysqli_query ($dbc, $q) or trigger_error("Query: $q\n<br />MySQL Error: " . mysqli_error($dbc));
if (mysqli_num_rows($r) == 0) { // Available.
// Create the activation code:
$a = md5(uniqid(rand(), true));
Here is your code converted to PDO.
// Make sure the email address is available:
$q = $dbc->query("SELECT user_id FROM users WHERE email=?");
$q->execute(array($e));
$r = $q->fetchColumn();
if (!$r) { // Available.
// Create the activation code:
$a = md5(uniqid(rand(), true));
Three things has been corrected
You have to always use a placeholder tp represent a variable in the query.
To get a single value from the result, fetchColumn have to be used instead of fetchAll
No need for the manual reporting, as PDO can report its errors automatically, if confugired properly, as described in this tutorial I wrote
I have a data object related to some other data objects and I am trying to build a reporting page for them.
So far I've got the code below in my page controller to display a form where I will begin to select filtering options for the report.
However I am getting this error due to the left join:
[Warning] Missing argument 2 for SQLQuery::addLeftJoin()
It would seem that the raw2sql is outputting this when I've debugged:
\'AgeRangeData\', \'CallEvent.AgeRangeData ID=AgeRangeData.ID)\'
I'm assuming that the backslashes is what is causing the error
public function ReportingFilter(){
$DataObjectsList = $this->dbObject('DataObjects')->enumValues();
$fields = new FieldList(
new DropdownField('DataObjects', 'Data Objects', $DataObjectsList)
);
$actions = new FieldList(
new FormAction("FilterObjects", "Filter")
);
return new Form($this, "ReportingFilter", $fields, $actions);
}
public function FilterObjects($data, $form){
$data = $_REQUEST;
$query = new SQLQuery();
$object = $data['DataObjects'];
$leftJoin = Convert::raw2sql("'" . $object . "', 'CallEvent." . $object . " ID={$object}.ID)'");
$query->selectField("CallEvent.ID", "ID");
$query->setFrom('`CallEvent`');
$query->setOrderBy('CallEvent.Created DESC');
$query->addLeftJoin($leftJoin);
return $query;
}
SQLQuery::addLeftJoin() takes two arguments. The first is the table to join on and the second is the "on" clause.
You want:
$query = new SQLQuery();
$query->addLeftJoin($object, '"CallEvent"."ID" = "' . $object . '"ID"');
You'd need to escape $object appropriately, of course.
NB: Your code looks a little fragile as you're not ensuring that you $object actually has a DB table. I recommend you use ClassInfo::baseDataClass($object). This will have the added benefit that it will also sanitise your class name and ensure it's a real class.
I'm working on a Laravel project that uses a form with multiple file inputs. If I submit the form with the first input empty and all other inputs with a file, then hasFile returns false. It will only return true if the first input contains a file.
if(Input::hasfile('file'))
{
// do something
}
This is the input array via Input::file('file). The small image input is empty, but the large is not. I'd like it to look at the whole array and if there any files present, then proceed with the "do something".
Array
(
[small] =>
[large] => Symfony\Component\HttpFoundation\File\UploadedFile Object
(
[test:Symfony\Component\HttpFoundation\File\UploadedFile:private] =>
[originalName:Symfony\Component\HttpFoundation\File\UploadedFile:private] => image_name.jpg
[mimeType:Symfony\Component\HttpFoundation\File\UploadedFile:private] => image/jpeg
[size:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 44333
[error:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 0
[pathName:SplFileInfo:private] => /Applications/MAMP/tmp/php/phpHILgX2
[fileName:SplFileInfo:private] => phpHILgX2
)
)
Is this expected behavior? Or, should it be looking at the entire array?
You can check by using the array key for example like below :-
HTML Input type File Element :
<input type="file" name="your_file_name[]" />
Laravel 5 : $request->hasFile('your_file_name.'.$key)
Laravel 4.2 : Input::hasFile('your_file_name.'.$key)
Taken from source:
/**
* Determine if the uploaded data contains a file.
*
* #param string $key
* #return bool
*/
public function hasFile($key)
{
if (is_array($file = $this->file($key))) $file = head($file);
return $file instanceof \SplFileInfo;
}
It seems that it only checks the first one from the array, head returns the first item from the array.
Since I can't comment, seems I'll have to post.
Ronak Shah's answer really should be marked the correct one here, and when I figured out why, it instantly had me saying "Sonnofa--" after 30-40 minutes trying to figure this... "mess" out.
Turns out to use hasFile() on an input array, you need to use dot notation.
So (using my own example) instead of
$request->hasFile("img[29][file]")
it needs to be
$request->hasFile("img.29.file")
That's certainly an eye-opener, given that PHP and dot notation don't really go together. Input arrays really are problem children.
here is a snippet that may help
if(Input::hasFile('myfile')){
$file = Input::file('myfile');
// multiple files submitted
if(is_array($file))
{
foreach($file as $part) {
$filename = $part->getClientOriginalName();
$part->move($destinationPath, $filename);
}
}
else //single file
{
$filename = $file->getClientOriginalName();
$uploadSuccess = Input::file('myfile')->move($destinationPath, $filename);
}
} else {
echo 'Error: no file submitted.';
}
Taken from
http://forumsarchive.laravel.io/viewtopic.php?id=13291
At the time of writing (Laravel 8) the Request class now supports arrays for the hasFile method, as from the source code:
/**
* Determine if the request contains the given file.
*
* #param string $name
* #param string|null $value
* #param string|null $filename
* #return bool
*/
public function hasFile($name, $value = null, $filename = null)
{
if (! $this->isMultipart()) {
return false;
}
return collect($this->data)->reject(function ($file) use ($name, $value, $filename) {
return $file['name'] != $name ||
($value && $file['contents'] != $value) ||
($filename && $file['filename'] != $filename);
})->count() > 0;
}
I'm having problems in understanding a part of the meaning of binding certain variable types in PDO and mysqli if the type given, in my case, seems to be meaningless. In the following code, the type bound (like i or s) gets ignored. The table row "wert_sortierung" in the database is INT(11). Regardingless if $val_int is really integer or not and if I bind it via i,s / PDO::PARAM_INT or _STR, the query always works, no break, no error or warning, that the types in the binding and database or variable itself don't fit.
<?
class PDOTest {
protected $pdo;
function __construct(){
$usr="usr";
$pwd="pwd";
$host="localhost";
$db="db";
$val_int="I'm a string";
$val_str="OP";
$querystring="SELECT wert_langtext FROM TB_wert WHERE wert_sortierung = ? AND wert_CD = ?";
try {
$db_info = "mysql:host=$host;dbname=$db"; // usually provided via require_once and during construction
$this->pdo = new PDO($db_info, $usr, $pwd);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$stmt = $this->pdo->prepare($querystring);
$stmt->bindValue(1,$val_int,PDO::PARAM_INT);
$stmt->bindValue(2,$val_str,PDO::PARAM_STR);
$stmt->execute();
$row_return = $stmt->fetchAll(PDO::FETCH_ASSOC);
$this->varprint($row_return);
$this->pdo = NULL;
}
catch (PDOException $ex) {
printf ('Es spricht:');
$this->printerror("Fehla! (" . $ex->getMessage() . ")");
$this->pdo = NULL;
exit();
}
printf("<br />-------<br />");
//Added for comparison
$mysqli = new mysqli($host, $usr, $pwd, $db);
$m_stmt = $mysqli->prepare($querystring);
$m_stmt->bind_param('is',$val_int, $val_str);
$m_stmt->execute();
$m_stmt->bind_result($row_return);
$m_stmt->fetch();
$this->varprint($row_return);
$m_stmt->close();
$mysqli->close();
}
private function printerror($txt) {
printf("<p><font color=\"#ff0000\">%s</font></p>\n",
htmlentities($txt));
}
private function varprint($var) {
echo "<br />";
echo "<pre>";
echo var_dump($var);
echo "</pre>";
}
}
new PDOTest();
?>
Please can anyone point out my error in reasoning.
It is actually Mysql's loose-typing that that deceived you.
As a matter of fact, regular Mysql queries can accept strings for the numberic values all right:
SELECT wert_langtext FROM TB_wert WHERE wert_sortierung = '1' AND wert_CD = '1';
while prepared statement just following this behavior.
However, a contrary situation is not that harmless. Addressing a string value with a number
SELECT wert_langtext FROM TB_wert WHERE wert_sortierung = 1;
will cause infinite number of warnings in case of wert_sortierung being of string type and some unexpected behavior, like matching for ALL the rows.
So, as a general advise I would suggest to always use 's' by default. The only drawback is PDO's emulated prepares and it can be easily worked around.
So, to answer your question explicitly - prepared statements just allow the same behavior as regular queries, adding nothing to it. Everything that possible with a regular query, is possible with prepared statement as well. And no, binding do not validate your data (however it should. Imn my class I test integer placeholders and throw an exception if no numeric value given)
function mysql_insert($data_array){
$sql = "insert into `". $this->table_name. '`';
$array_keys = array_keys($data_array);
$array_keys_comma = implode(",\n", preg_replace('/^(.*?)$/', "`$1`", $array_keys));
for($a=0,$b=count($data_array); $a<$b; $a++){ $question_marks .="?,"; }
$array_values = array_values($data_array);
$array_values_comma = implode(",", $array_values);
$sql.= " ($array_keys_comma) ";
$sql.= " values(". substr($question_marks, 0,-1) .")";
$prepare = $this->connDB->prepare($sql);
$insert = $prepare->execute(array($array_values_comma));
}
I want to creat like this universal functions, $data_array-comes from $_POST
This function will work for all form. But i dont know what is my wrong :S
I don't know what is my wrong
That's quite easy to know: number of bound variables does not match number of tokens.
I want to creat like this universal functions, $data_array-comes from $_POST
Here you go: Insert/update helper function using PDO
$array_values_comma is a scalar after you implode() the array. So you always pass an array of one element to your execute() function. You should pass $array_values.
Here's how I'd write this function:
function mysql_insert($data_array){
$columns = array_keys($data_array);
$column_list_delimited = implode(",",
array_map(function ($name) { return "`$name`"; }, $columns));
$question_marks = implode(",", array_fill(1, count($data_array), "?"));
$sql = "insert into `{$this->table_name}` ($column_list_delimited)
values ($question_marks)";
// always check for these functions returning FALSE, which indicates an error
// or alternatively set the PDO attribute to use exceptions
$prepare = $this->connDB->prepare($sql);
if ($prepare === false) {
trigger_error(print_r($this->connDB->errorInfo(),true), E_USER_ERROR);
}
$insert = $prepare->execute(array_values($data_array));
if ($insert === false) {
trigger_error(print_r($prepare->errorInfo(),true), E_USER_ERROR);
}
}
A further improvement would be to do some validation of $this->table_name and the keys of $data_array so you know they match an existing table and its columns.
See my answer to escaping column name with PDO for an example of validating column names.