I have answers table with fields id player_id read_status
I am trying to update read_status:
$this->Answer->updateAll(
array(
'Answer.' . "'" . $data['field'] . "'" => "'" . trim(base64_decode($data['option'])) . "'"
),
array(
'Answer.id' => trim(base64_decode($data['id']))
)
);
The following fields are dynamic and coming from AJAX Request:
$data['field'] contains read_status
$data['option'] contains base64 encoded yes
$data['id'] contains base64 encoded id
The error I am getting is:
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Answer.'read_status'' in 'field list'
SQL Query:
UPDATE
`skii`.`answers` AS `Answer`
LEFT JOIN
`skii`.`players` AS `Player` ON (`Answer`.`player_id` = `Player`.`id`)
SET
`Answer`.`'read_status'` = 'yes'
WHERE
`Answer`.`id` = 2
Notice: If you want to customize this error message, create app\View\Errors\pdo_error.ctp
Don't do that
The conditions you're generating are:
WHERE
`Answer`.`id` = 2
There is no reason to use updateAll for that, the primary use cases for updateAll are:
Updating multiple records
Updates by not-primary-key
Updates such as incrementing a counter atomically
Call save
Instead, just call saveField:
$this->Answer->id = $id;
$this->Answer->saveField($field, $val);
or save:
$this->Answer->id = $id;
$this->Answer->save(array($field => $val));
Validate your inputs
If you choose to continue using the code in the question know that it is dangerous.
Feeding user input directly to updateAll allows for the possibility to inject arbitrary SQL. Ensure the data is the data you expect:
With the updateAll call there's nothing to prevents someone submitting as $field:
"read_status = 'yes' AND correct ="
achieving this sql:
SET `Answer`.`read_status` = 'yes' AND correct = 'yes'
It is generally a bad idea to ever put user input in the key of a CakePHP model array (update, conditions, order) as the key is not expected to be potentially malicious by CakePHP and therefore not subject to the same escaping logic applied to values.
Therefore, escape all user input:
$ds = $this->Answer->getDatsource();
$id = (int)trim(base64_decode($data['id']));
$field = $this->Answer->escapeField((base64_decode($data['field']));
$val = $ds->value(trim(base64_decode($data['option']))), $field);
With the above logic and attempting the same injection as shown in the first example the result would be:
SET `Answer`.``read_status` = 'yes' AND correct =` = 'yes';
Which would simply fail rather than permit users to arbitrarily manipulate the database.
Note that the base64 encoding, if it's been added as a "security" measure, does nothing.
It seems the proble is that you are escaping the field name with single quotes:
`Answer`.`'read_status'` = 'yes'
should be
`Answer`.`read_status` = 'yes'
The following change should fix that:
$this->Answer->updateAll(
array('Answer.' . $data['field'] => trim(base64_decode($data['option']))),
array('Answer.id' => trim(base64_decode($data['id'])))
);
Try this :-
$this->Answer->updateAll(
array(
'Answer.' . $data['field'] => "'" . trim(base64_decode($data['option'])) . "'"
),
array(
'Answer.id' => trim(base64_decode($data['id']))
)
);
Related
I keep having problems with quotes in relation to a table update. I'm sending a Post with several values from a form, and then update a table with them. For the code to work, I need to wrap keys with backslash ($ColumnaString), and values with single quotes ($ValueString). This works OK. My problem is that occasionally I want to update to NULL (when $value==""). But my present code don't do that. Can somebody spot the problem?
$id_tag=trim($_POST['id']);
foreach($_POST as $key=>$value){
if ($key!="UpdatePeople"){
$ColumnaString="`".$key."`";
$ValueString="'".iconv('UTF-8', 'ISO-8859-1//TRANSLIT', utf8_encode($value))."'";
if ($key=="In_Date" and $value=="") {$ValueString==NULL;} //Hereis my problem I think
$link->query("UPDATE MyTable SET ".$ColumnaString."=".$ValueString." WHERE `id`=".$id_tag."");
}
}
You could check $id_tag and create a proper part of sql code
$str = ($id_tag ='' ) ? ' is null ' : ' = '.$id_tag;
$link->query("UPDATE MyTable SET ".$ColumnaString." = ".$ValueString." WHERE `id`".str."");
and for $vale
if ($key=="In_Date" and $value=="") { $ValueString = 'NULL' ;} //Hereis my problem I think
check your database if the columns is defined as NOT NULL
Alright, So I am trying to make a query that searches the table PRIV for any columns that were selected in the checkboxs that = Yes or No.
Here is the code.
if(isset($_POST['submit']))
{
$fini = $_POST['chk'];
$fila = $_POST['ends'];
$qMarks = str_repeat('?,', count($fini) - 1) . '?';
$stmt = $con->prepare("SELECT * FROM priv WHERE `$qMarks` = `$fila`");
$stmt->execute($fini);
while($myR=$stmt->fetch(PDO::FETCH_ASSOC))
{
echo $myR['ident'];
echo "<br>";
}
}
As you can see, $fini represents the checkboxs in an array form that were selected.. the possible numbers in $fini are op1, op2 all the way through op24
$fila represents a simple Yes or No Selector..
For instance.. If I was to select checkbox 2 and 3 then $fini array would be op2, op3 and if I selected enabled on the selector then $fila would be Yes
This is the error I am getting.
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42S22]: Column not found: 1054 Unknown column ''op1'' in 'where clause'' in
It's saying unknown columns op1.. Which makes no sense because I have columns op1 - op24
Could someone please help me with this.
The error message shows that the 'op1' column (with quotes) is being looked for, which obviously does not exist. The quotes are there because you passed these values as string parameters.
But that could never work. Parameters are intended to pass literal values, not column names.
The thing you want to do does not go well with parameters. Instead I would suggest the following code. Comments should clarify each step:
// Generate array of valid column names
$columns = array_map(function ($i) { return "op$i"; }, range(1,24));
// Ensure the provided data is acceptable -- remove what is not:
$fila = $_POST['ends'] == 'Yes' ? 'Yes' : 'No'; // only Yes or No are allowed
$fini = array_intersect($columns, $_POST['chk']); // only real column names are allowed
// You need to treat the case when no checkboxes are checked:
if (count($fini) == 0) die("You need to check at least one checkbox.");
// Make $fila also an array with just as many elements as $fini, and wrap
// each value (Yes or No) in quotes:
$fila = array_fill(0, count($fini), "'$fila'");
// turn both arrays into comma-separated strings, and compare tuples
$sql = "SELECT * FROM priv
WHERE (" . implode(',', $fini) . ") = (" . implode(',', $fila) . ")";
$stmt = $con->prepare($sql);
$stmt->execute(); // no parameters
// ... etc...
Considerations
It is not so good practice to design a database table with 24 columns which serve a similar purpose. Instead you should normalise your database, and put these values in rows instead of in columns.
I'm trying to use the typo3 update function with the mysql CONCAT function. Can you tell me how to manage that? What I tried:
$updateArray = array("field" => 'CONCAT( field'.','.$toAppend.')');
$GLOBALS['TYPO3_DB']->exec_UPDATEquery ('table','id = '.'"'.$some_id.'"',$updateArray);
That does not work, because that query is executed:
UPDATE table
SET
pagesEdited='CONCAT( field,'value')'
WHERE
id = "id"
As you see, the concat function is escaped.
The reference documentation isn't very clear about it, however, just appending TRUE to your parameters of the update function should disable quoting:
$GLOBALS['TYPO3_DB']->exec_UPDATEquery ('table','id = '.'"'.$some_id.'"',$updateArray, TRUE);
That also means that you will have to do your own input sanitization before lauching the query, if you haven't already:
$toAppend = $GLOBALS['TYPO3_DB']->fullQuoteString($toAppend, "");
Have a look at the noQuote parameter of the fullQuoteArray() method of TYPO3\CMS\Core\Database\DatabaseConnection that is used by exec_UPDATEquery():
#param boolean|array $noQuote List/array of keys NOT to quote (eg. SQL functions) - ONLY for associative arrays
And when you take a kloser look ath this method, you will see that a simple true does not do the trick as expected. Simply use a list of fields (comma separated list) or an array to let TYPO3 know which fields should not be escaped.
In your case it would look like this:
$updateArray = array(
'field' => 'CONCAT(field,' . $GLOBALS['TYPO3_DB']->fullQuoteString($toAppend, 'table') . ')',
);
$where = 'id = ' . $GLOBALS['TYPO3_DB']->fullQuoteString($some_id, 'table');
$GLOBALS['TYPO3_DB']->exec_UPDATEquery ('table', $where, $updateArray, 'field');
I have a piece of code that looks like this:
// get media table columns
$media_columns = $this->many( "SHOW COLUMNS FROM media;" );
$media_fields = array(); // array to filter out unnecessary col data
$pk_name = 'ignore_this';
foreach( $media_columns as $col ) {
$field = $col['Field'];
if( $field !== $pk_name ) {
array_push($media_fields, '`'.$field.'`');
}
}
$fields_str = "(".implode(",", $media_fields).")"; // put in string
// we will be overriding the campaign_uid with parent_uid
$insert_str = str_replace("`campaign_uid`", "'$parent_uid'", implode(',', $media_fields) );
// duplicate draft media, pointing to parent campaign
$this->none(
"INSERT INTO media ".
"$fields_str ".
"SELECT $insert_str ".
"FROM media WHERE `campaign_uid`='$campaign_uid' "
);
Which throws an error:
exception 'Exception' with message 'ADO Error: Unknown column 'margin-left' in 'field list' { INSERT INTO media (`ignore_this`,`nonprofit_uid`,`campaign_uid`,`meta_id`,`image_name`,`url`,`type`,`subtype`,`mark`,`last_updated`,`deleted`,`margin-left`,`margin-top`)
SELECT `ignore_this`,`nonprofit_uid`,'XXXXXX',`meta_id`,`image_name`,`url`,`type`,`subtype`,`mark`,`last_updated`,`deleted`,`margin-left`,`margin-top` FROM media
WHERE `campaign_uid`='XXXXXXXXXXX }'
Before you ask about the funky sql wrapper functions: don't. I've inherited a mess of a codebase from my predecessor, and am largely locked into using his functions.
For the same reason, we have hyphens in the mysql column names. Because it's margin-left that fails, I suspect that this is the problem, but there's enough hard-coded references to that column name all over the place the refactoring isn't a very attractive option.
The funny part is, I'm pulling the field names directly from a SHOW COLUMNS call, and escaping them with ticks. I don't understand how the column can't be found if it was just read from the DB a second ago.
Any help is appreciated.
Don't use show columns. That was never really intended for how you're using it. Use the information_schema meta-db instead:
select COLUMN_NAME
from information_schema.COLUMNS
where (TABLE_SCHEMA='name of db') AND (TABLE_NAME = 'name of your table')
I've already read Passing an array to a query using a WHERE clause which is basically what I am doing, but with strings instead of integers. I am having an issue with the WHERE clause.
$codes_imp = "'" . implode("','", $codes) . "'";
$passwords_imp = "'" . implode("','", $passwords) . "'";
$comments_imp = "'" . implode("','", $comments) . "'";
$set_pass_query = "INSERT INTO users (password, comments) VALUES ($passwords_imp, $comments_imp) WHERE Code IN ($codes_imp)";
When executed, the query looks like this:
INSERT INTO users (password, comments)
VALUES ('password1', 'password2', 'password3', 'comment1', 'comment2', 'comment3')
WHERE Code IN ('code1', 'code2', 'code3')
All columns in the table are of type VARCHAR. Clearly I have a syntax error (as it is telling me), but I am not sure how to construct this properly.
You are trying to constrain an INSERT query with a WHERE clause. That's a big no-no.
Either you want to UPDATE, or you need to drop the WHERE
What exactly are you trying to accomplish?
You need to use UPDATE and not INSERT, to alter existing db rows.
You could use a loop construct like the foreach loop.
E.g:
foreach($codes_imp as $key=>$code){
$query="UPDATE users SET password='$passwords_imp[$key]', comments='$comments_imp[$key]' WHERE Code='$code'"
[Code to execute the query goes here]
}
N.B: We need to use a loop construct because UPDATE queries can run only on one db row at a time.
Alternative method:
Instead of using loops you could use the CASE WHEN ELSE END syntax in Mysql.
To know how to use this, please refer:
https://stackoverflow.com/a/2528188/749232
http://www.kavoir.com/2009/05/mysql-update-multiple-rows-with-one-single-query.html