I have some text stored in a table. I want to replace all the expressions that look like this : [%parameter_name] with the corresponding value stored in another table.
All the parameters and in which column I must fetch their value are stored in a third column.
I tried to make a function to put all the needed patterns and their value in an array. However, it gives me a fatal error. Why?
Here is the code :
$search = $db->prepare("
SELECT *
FROM table
WHERE id = ?");
$search->execute(array($id));
$search->setFetchMode(PDO::FETCH_OBJ);
while($result = $search->fetch()){
$search2 = $db->prepare("
SELECT parameter_name,
read_from
FROM pattern
WHERE type = ?");
$search2->execute(array(strtolower($result->type)));
$search2->setFetchMode(PDO::FETCH_OBJ);
while($pattern = $search2->fetch()){
array_push($patterns, '/\[%'.$result->type.'\.'.$pattern->parameter_name.'\]/i');
$column = explode(',', $pattern->read_from);
if(count($column) == 1){
$col = $column[0];
// ERROR ON THE LINE BELOW
$value = $result->$col;
}
else{
$value = 0;
foreach($column as $col){
// BUT NOT ON THE ONE BELOW
$value += $result->$col;
}
}
array_push($replacements, $value);
}
}
Related
The first part of my code creates some entries in a table using $_POST.
foreach ($_POST['form_item'] as $key => $value) {
$item = $_POST['form_item'][$key];
$barcode = $_POST['form_barcode'][$key];
$task = $_POST['form_task'][$key];
$bottom_items = $pdo->prepare("INSERT INTO carpet_items_extra (`item_id`,`item_task`, `item_barcode`) VALUES ('$log_id', '$task', '$barcode')");
$bottom_items->execute();
The next part contains the data I need to update the entries with.
if(isset($_POST['form_price_standard'][$key]) && $_POST['form_price_standard'][$key] != ''){
$price_standard = $_POST['form_price_standard'][$key];
}
else{
$price_standard = 0;
}
if(isset($_POST['form_price_daily_1'][$key]) && $_POST['form_price_daily_1'][$key] != '' && isset($_POST['form_duration_2'][$key]) && $_POST['form_duration_2'][$key] != ''){
$price_daily_1 = $_POST['form_price_daily_1'][$key];
$duration_2 = $_POST['form_duration_2'][$key];
}
else{
$price_daily_1 = 0;
$duration_2 = 0;
}
$update = $pdo->prepare("UPDATE carpet_items_extra SET `price_standard` = '$price_standard', `price_daily_1` = '$price_daily_1', `duration_2` = '$duration_2' WHERE item_id = '$log_id AND item_task = '$task' AND item_barcode = '$barcode'");
$update->execute();
}
The problem is when the data is only from the first isset it's saved as it should be, but when there's data in the second isset as well, only the first row in the table gets update.
How can I differentiate between the two?
I have tried using for to execute the query once for every $barcode item, as well as using nested foreach.
The result though was multiple extra entries in the database table.
Uncaught mysqli_sql_exception: Truncated incorrect DOUBLE value: '0-' in ... Stack trace: #0 ...(68): mysqli->query('UPDATE `Results...') #1 {main} thrown in ... on line 68
That's the error I am getting with the ellipses representing the file pathway.
The php I have:
for($i = 1; $i < $maxQuestions; $i++){
$answer = $_POST["question$i"] == "Yes" ? "1-" : "0-";
$connection->query("UPDATE `Results`
SET `question$i` = `question$i` + '$answer'
WHERE `ID` = '$id'");
}
The problem is with the SET `question$i` = `question$i` + '$answer' as I am trying to basically keep a history of the question's answers. For example, I may want the stored data to go from "0-" to "0-1-". How do you += a string with php/sql?
EDIT:
I have tried SET `question$i` = concat(`question$i` + '$answer') and I am getting the same error.
I changed it to
for($i = 1; $i < $maxQuestions; $i++){
$answer = $_POST["question$i"] == "yes" ? "1-" : "0-";
$qColumn = "question" . strval($i);
$questionData = $data["question$i"] . $answer;
$connection->query("UPDATE `Results`
SET `$qColumn` = '$questionData'
WHERE `ID` = '$id'");
}
This worked, but I'm still not sure why my initial code did not work. If someone could post a better answer/solution and why my initial code didn't work, please do. Thanks!
In mysql You can do it dierctly using concat this way
SET `question$i` =concat(`question$i`, '$answer')
You should not have column names ending with numbers because this is an indicator that your schema is not correct. You should normalise the database and have questions as a separate tables joined to your results table. Your results should not be concatenated into a single column either. Have a separate row for each result.
However, if you want to achieve this with your current set-up you could use CONCAT(). The query should look similar to this:
$types = '';
$setString = [];
$values = [];
for($i = 1; $i < $maxQuestions; $i++){
// concat types
$types .= 's';
// gather values
$values[] = isset($_POST["question$i"]) ? "1-" : "0-";
// build SET statement
$columnName = "question" . $i;
$setString[] = $columnName.' = CONCAT('.$columnName.', ?)';
}
$sql = "UPDATE Results SET ".implode(', ', $setString).' WHERE ID = ?';
$stmt = $connection->prepare($sql);
$stmt->bind_param($types, ...$values);
$stmt->execute();
I am trying to build a search query. I got following error, It seems syntax error of sql.
SQLSTATE[HY093]: Invalid parameter number (SQL: select * from products
where styles = Abstract , Abstract and subject = ? )
Why this error occurred ?
How to figure it out ?
My code as follows
if (isset($request->search)) {
//GET ALL INPUT FROM THE REQUEST
$query_strings = $request->all();
//PULL OUT ANY EMPTY FIELD FROM THE REQUEST
$filtered_array = array_filter($request->all());
//remove the last item
array_pop($filtered_array);
//BUILD A QUERY
$sql = array();
$values = array();
$x = 1;
foreach ( $filtered_array as $key =>$value ) {
if($x < count($filtered_array)){
$sql[]=" $key = ? and ";
$values[] =" $value , ";
} else {
$sql[]=" $key = ? ";
$values[] =" $value ";
}
$x++;
}
$fields = join(' ', $sql);
$v = join(' ',$values);
dd( \DB::select("select * from products where {$fields} ", [$v]));
}
When you're passing some values, you should add ? placeholder:
\DB::select("select * from products where ?", [$value]));
This is a bit of a stretch and I doubt it will work as is on the first try. But I really suggest you try and make use of the Laravel's query builder.
This code assumes you're passing 'products' table column names as names of GET or POST parameters and values you want to query by as values. For example:
url.com?price=200&size=2
Where 'price' and 'size' are column names of 'products' table.
Code:
// Check if request has 'search' parameter
if($request->has('search')) {
// $filtered_array now has all parameters that were passed to the controller
$filtered_array = $request->all();
// Start a query on table 'products'. Laravel style (more: https://laravel.com/docs/5.3/queries)
$query = \DB::table('products');
// For each parameter passed to the controller, we make "and where products.$key = $value" statement in the query
foreach($filtered_array as $key => $value) {
$query->where($key, '=', $value);
}
// Tell the query builder to get the results and save it to $results variable
$results = $query->get();
}
This will undoubtedly cause a lot of errors as anyone can send anything as GET/POST parameters and query by that (which will throw SQL error that the column doesn't exist).
You should change the $filtered_array = $request->all() to:
$filtered_array = $request->only(['id', 'price', 'size']);
This way you will store only the parameters you specify in the ->only(array) in the $filtered_array and ignore all the others. So you should replace 'id', 'price' and 'size' with all the columns of the 'products' table you wish to query by.
I have an array like the following:
tod_house
tod_bung
tod_flat
tod_barnc
tod_farm
tod_small
tod_build
tod_devland
tod_farmland
If any of these have a value, I want to add it to an SQL query, if it doesnt, I ignore it.
Further, if one has a value it needs to be added as an AND and any subsequent ones need to be an OR (but there is no way of telling which is going to be the first to have a value!)
Ive used the following snippet to check on the first value and append the query as needed, but I dont want to copy-and-paste this 9 times; one for each of the items in the array.
$i = 0;
if (isset($_GET['tod_house'])){
if ($i == 0){
$i=1;
$query .= " AND ";
} else {
$query .= " OR ";
}
$query .= "tod_house = 1";
}
Is there a way to loop through the array changing the names so I only have to use this code once (please note that $_GET['tod_house'] on the first line and tod_house on the last line are not the same thing! - the first is the name of the checkbox that passes the value, and the second one is just a string to add to the query)
Solution
The answer is based heavily upon the accepted answer, but I will show exactly what worked in case anyone else stumbles across this question....
I didnt want the answer to be as suggested:
tod_bung = 1 AND (tod_barnc = 1 OR tod_small = 1)
rather I wanted it like:
AND (tod_bung = 1 OR tod_barnc = 1 OR tod_small = 1)
so it could be appended to an existing query. Therefore his answer has been altered to the following:
$qOR = array();
foreach ($list as $var) {
if (isset($_GET[$var])) {
$qOR[] = "$var = 1";
}
}
$qOR = implode(' OR ', $qOR);
$query .= " AND (" .$qOR . ")";
IE there is no need for two different arrays - just loop through as he suggests, if the value is set add it to the new qOR array, then implode with OR statements, surround with parenthesis, and append to the original query.
The only slight issue with this is that if only one item is set, the query looks like:
AND (tod_bung = 1)
There are parenthesis but no OR statements inside. Strictly speaking they arent needed, but im sure it wont alter the workings of it so no worries!!
$list = array('tod_house', 'tod_bung', 'tod_flat', 'tod_barnc', 'tod_farm', 'tod_small', 'tod_build', 'tod_devland', 'tod_farmland');
$qOR = array();
$qAND = array();
foreach ($list as $var) {
if (isset($_GET[$var])) {
if (!empty($qAND)) {
$qOR[] = "$var = 1";
} else {
$qAND[] = "$var = 1";
}
$values[] = $_GET[$var];
}
}
$qOR = implode(' OR ', $qOR);
if ($qOR != '') {
$qOR = '(' . $qOR . ')';
}
$qAND[] = $qOR;
$qAND = implode(' AND ', $qAND);
echo $qAND;
This will output something like tod_bung = 1 AND (tod_barnc = 1 OR tod_small = 1)
As the parameter passed to $_GET is a string, you should build an array of strings containing all the keys above, iterating it and passing the values like if (isset($_GET[$key])) { ...
You could then even take the key for appending to the SQL string.
Their are a lot of ways out their
$list = array('tod_house', 'tod_bung', 'tod_flat', 'tod_barnc', 'tod_farm', 'tod_small', 'tod_build', 'tod_devland', 'tod_farmland');
if($_GET){
$query = "";
foreach ($_GET as $key=>$value){
$query .= (! $query) ? " AND ":" OR ";
if(in_array($key,$list) && $value){
$query .= $key." = '".$value."'";
}
}
}
Sure you have to take care about XSS and SQL injection
If the array elements are tested on the same column you should use IN (...) rather than :
AND ( ... OR ... OR ... )
If the values are 1 or 0 this should do it :
// If you need to get the values.
$values = $_GET;
$tod = array();
foreach($values as $key => $value) {
// if you only want the ones with a key like 'tod_'
// otherwise remove if statement
if(strpos($key, 'tod_') !== FALSE) {
$tod[$key] = $value;
}
}
// If you already have the values.
$tod = array(
'tod_house' => 1,
'tod_bung' => 0,
'tod_flat' => 1,
'tod_barnc' => 0
);
// remove all array elements with a value of 0.
if(($key = array_search(0, $tod)) !== FALSE) {
unset($tod[$key]);
}
// discard values (only keep keys).
$tod = array_keys($tod);
// build query which returns : AND column IN ('tod_house','tod_flat')
$query = "AND column IN ('" . implode("','", $tod) . "')";
I have a form that displays a Selection ID, Selection, and Definition pairing from a database. The form is dynamic...depending on the user, there could be any number of these pairings. Here is an example of three pairings:
Selection ID, Selection, Definition
Selection ID, Selection, Definition
Selection ID, Selection, Definition
The page displays just fine, but if the user wants to edit a Selection or Definition, I receive the following error when the form is submitted (Note: Line 41 is my Update query):
"Notice: Undefined offset: 3 in (link to my php file) on line 41"
I assume that the notice is telling me that the query is not reading the information in my three arrays...but I don't know what I should be putting in my query so it will read properly. Thank you very much for your help.
if(isset($_POST['submit'])){
$selection_id = array();
$selection = array();
$definition = array();
foreach ($_POST as $key => $value){
// If array variable starts with "pd_selection_id_for_" save to $selection_id array, otherwise continue to the next array.
if(strpos($key, 'pd_selection_id_for_') !== false){
$selection_id[] = mysql_real_escape_string($value);
}else if(strpos($key, 'selection_for_') !== false){
$selection[] = mysql_real_escape_string($value);
}else if(strpos($key, 'definition_for_') !== false){
$definition[] = mysql_real_escape_string($value);
}
}
// Count one of the arrays to select the paired fields and update the database.
$total = count($definition);
for ($i=1; $i <= $total; $i++){
// Update query for the paired selections and definitions.
$query = mysql_query("UPDATE `pd_selections` SET `pd_selection` = '$selection[$i]', `pd_definition` = '$definition[$i]' WHERE `pd_selection_id` = '$selection_id[$i]' ") or die(mysql_error());
}
}
Minor syntax error the fix for Line 41 is below:
$query = mysql_query("UPDATE `pd_selections` SET `pd_selection` = '".$selection[$i]."', `pd_definition` = '".$definition[$i]."' WHERE `pd_selection_id` = '".$selection_id[$i]."'") or die(mysql_error());
Undefined Offset error means that the position that you are trying to access in your array is not set and therefore its not defined.
Problem you have is that your arrays are not initialized at the index you are trying to access from loop, try this:
$i = 0;
foreach ($_POST as $key => $value){
//initialize array at position $i
$selection_id[$i] = $selection[$i] = $definition[$i] = '';
if(strpos($key, 'pd_selection_id_for_') !== false){
$selection_id[$i] = mysql_real_escape_string($value);
}else if(strpos($key, 'selection_for_') !== false){
$selection[$i] = mysql_real_escape_string($value);
}else if(strpos($key, 'definition_for_') !== false){
$definition[$i] = mysql_real_escape_string($value);
}
$i++;
}
this way you know that all your arrays size are same and therefore will be set on same positions that other arrays are set.