I want to be able to remove quotations from a field on or abouts the name of 'quote'. On post, all my field names and values get matched up and put into an array then enter to the database. Before the SQL is built and after I build the value-key array, how can I single out the field quote, remove the quotation marks that the user inputted, and then add/keep the content in the $values array for my SQL? The questionable area starts with the comment "remove quotes"
public function insertIntoDb($table, $carryUrl = NULL, $ext = '')
{
if (in_array($table, $this->disallow_insert)) {
self::show_error("Inserting into the table '{$table}' is not possible, check the configuration file if this is an error.");
} elseif (!isset($table)) {
self::show_error('Missing `table` parameter in ' . __FUNCTION__);
}
$resultInsert = Nemesis::query("SHOW COLUMNS FROM {$table}");
if (!$resultInsert) {
self::show_error(QUERY_ERROR);
}
$fieldnames = array();
if ($resultInsert->num_rows > 0) {
while ($row = $resultInsert->fetch_array()) {
$fieldnames[] = $row['Field'];
$values = array_intersect_key($_POST, array_flip($fieldnames));
// $values = array_filter($values, function($x) { return $x !== ''; });
// <5.3 $values = array_filter($values, create_function('$x', 'return $x !== "";'));
}
}
// remove quotes for testimonials
if (array_key_exists('quote', array_change_key_case($values, CASE_LOWER))) {
$values['quote'] = preg_replace("/<!--.*?-->/", "", $values); // remove quotes
}
// filter the array
$values = self::filter($values);
$sql = sprintf("INSERT INTO %s (created, created_by, %s) VALUES (NOW(), '$_SESSION[user_id]', '%s')", $table, implode(', ', array_keys($values)), implode("', '", $values));
if ($this->debug) {
echo '<p>' . $sql . '</p>';
} elseif (Nemesis::query($sql)) {
$msg = new Messages();
$msg->add('s', QUERY_INSERT_SUCCESS);
if ($table == 'projects') {
$msg = new Messages();
$msg->add('s', "Information was added to the database. Time to add images!");
}
if (!is_null($carryUrl) && isset($carryUrl)) {
redirect($carryUrl . '?id=' . $_POST['id'] . '&table=' . $table . $ext);
}
} else {
self::show_error(QUERY_ERROR);
}
}
preg_replace is a function that returns a value, not a void. You'll need to assign the returned value back to $values['quote']:
// remove quotes for testimonials
if (array_key_exists('quote', array_change_key_case($values, CASE_LOWER))) {
$values['quote'] = preg_replace("/(\"|')/", "", $values['quote']); // remove quotes
}
Related
When is Array defined in string (like in sample below), is possible get the information of this Arrays?
$id = 1;
$query =
"
SELECT *
FROM category
WHERE
id > " . [$id, 'int'] . " AND
title LIKE " . ['%test%', 'str'] . "
ORDER BY id ASC
";
$select = sql ($query);
var_dump($query) // output
//SELECT * FROM category WHERE id > Array AND title LIKE Array ORDER BY id ASC
/*
var_dump ($query->my_defined_arrays_are)
[0] => 1
[1] => '%test%'
*/
i need this for better orientation in most complex queries for $sql->bind_param();
SOLUTION:
I created small function bind() which create and store the bind data and then send it to the sql() function where are processed. This works on all queries types (SELECT, INSERT, UPDATE, DELETE..etc.).
Important for me is clear and easy readable code.
Query:
$query =
"
SELECT *
FROM category
WHERE
id > " . bind('1', 'int') . " AND
title LIKE " . bind('%test%', 'str') . "
ORDER BY id ASC
";
$select = sql ($query, $bind);
/*
var_dump ($query)
SELECT * FROM category WHERE id > {Bind_Array} AND title LIKE {Bind_Array} ORDER BY id ASC
*/
Functions:
function bind($param, $type) {
global $bind;
$bind[] = $param . ', ' . $type;
return '{Bind_Array}';
}
function sql($query, $bind_param = []) {
global $settings, $bind;
$bind = null; // clean variable; must be empty for all next operations
$mysqli = new mysqli (
$settings['db_hostname'],
$settings['db_username'],
$settings['db_password'],
$settings['db_database']
);
if ($mysqli->connect_errno) {
echo 'Failed to connect to MySQL: (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error;
return;
}
if (!$mysqli->set_charset('utf8')) {
echo 'Error loading character set utf8: (' . $mysqli->character_set_name() . ') ' . $mysqli->error;
return;
}
if ($bind_param != null) {
unset ($tmp_bind, $tmp_type);
// reserve first key
$tmp_bind[0] = null;
// replace all occurences string in query
$query = preg_replace ('/({Bind_Array})/', ' ?', $query);
// create parameters from array
foreach ($bind_param as $params) {
// explode and clean parametres
$param = array_map ('trim', explode (',', $params));
if (count ($param) != 2) {
echo 'Too much or less parameters!';
return;
}
// first is content
$tmp_bind[] = $param[0];
// second is type; create right format
$tmp_type .= str_replace (array ('int', 'str', 'double'), array ('i', 's', 'd'), $param[1]);
}
// set types to the first reserved key
$tmp_bind[0] = $tmp_type;
// replace previdous incoming data with new created
$bind_param = $tmp_bind;
}
if (!($sql = $mysqli->prepare($query))) {
echo 'Prepare failed: (' . $mysqli->errno . ') ' . $mysqli->error;
$mysqli->close();
return;
}
if (!empty ($bind_param) && $type = array_shift ($bind_param)) {
// $sql->bind_param()
call_user_func_array (array ($sql, 'bind_param'), array_merge (array ($type), array_map (function (&$item) { return $item; }, $bind_param)));
}
if (!$sql->execute()) {
echo 'Execute failed: (' . $sql->errno . ') ' . $sql->error;
$sql->close();
return;
}
if (strpos ($query, 'SELECT ') !== false || strpos ($query, 'SHOW ') !== false) {
// proceed this only if is SELECT or SHOW query
if (!($res = $sql->get_result())) {
echo 'Getting result set failed: (' . $sql->errno . ') ' . $sql->error;
$res->close();
return;
}
// store data to $output for use
for ($row_no = ($res->num_rows - 1); $row_no >= 0; $row_no --) {
$res->data_seek($row_no);
$output[$row_no] = $res->fetch_assoc();
}
$res->close();
}
$sql->close();
unset ($tmp_bind);
return $output;
}
The answer to your question is "No". When you add an array to a string, you get a string, and the original array is lost in the string "Array".
So -- why are you doing this?
My guess is that you're trying to come up with a compact representation of a query - a single object containing information on the query and its parameters (if any). This can be done, but requires some code to go with it.
For example you can create a class of your own holding the query in PDO format, with placeholders:
SELECT * FROM category WHERE id > :param1 ...
and also an array of parameters with their types:
[ 'param1' => 'int', ... ]
Then you might need a __toString() method to yield a string representation that is of use for you. The above representation can immediately be used by PDO.
Now, to specify a query with its parameters, you can use a compact representation not too unlike the one you used, leveraging an array of arrays (note that there is no string concatenation here, but rather array concatenation):
$query = ["SELECT * FROM tbl WHERE id >",['int']," AND ..." ...];
To convert from this "shorthand" to the more useable PDO_String / PDO_Param_Array representation, you could walk $query concatenating all non-string elements with placeholder parameters:
$queryString = '';
$queryParams = [ ];
$n = 1;
foreach ($query as $item) {
if (is_string($item)) {
$queryString .= $item;
} else {
$queryString .= ':param' . $n;
$queryParams[":param{$n}"] = $item[0];
$n++;
}
}
I'm doing a basic sql string builder, and I'm trying to use ternary operators to conditionally feed a null value, or the value of the datetime into the statement.
Basic syntax of the update statement if all values are present.
UPDATE tblRecvLog
SET ScheduledTime = 'datetime',
ScaleInTime = 'datetime',
SampleToLabTime = 'datetime',
ScaleWeight = 'weight',
SealTop = 'sealnumber',
SealBottom = 'sealnumber'
WHERE pkRecvLogID = 'uniqueid';
I'm receiving these values from an ajax post, and they're valid values in my $_POST data, all of the encoding and decoding being done appropriately. When a datetime is not specified on the form and the user submits an update to the table record, I want to write a null value to the database. I'm trying to properly use ternary operator in my sql string builder to make this work.
$sql = "UPDATE tblRecvLog SET "
. ($ScheduledTime == '') ? "ScheduledTime = NULL," : "ScheduledTime = '{$ScheduledTime}',"
. ($ScaleInTime == '') ? "ScaleInTime = NULL," : "ScaleInTime = '{$ScaleInTime}',"
. ($SampleToLabTime == '') ? "SampleToLabTime = NULL," : "SampleToLabTime = '{$SampleToLabTime}',"
. "ScaleWeight = '{$ScaleWeight}',
SealTop = '{$SealTop}',
SealBottom = '{$SealBottom}'
WHERE pkRecvLogID = '{$pkRecvLogID}'";
The part I'm not wrapping my head around:
Dates need to be wrapped in '' for SQL server.
My use of ' and " is making it confusing.
I like to use vsprintf for this sort of thing, I think it makes things nicer to read. You can read more about the format specifiers. In this example I am just using %s to represent strings.
<?php
$query = "
UPDATE
tblRecvLog
SET
ScheduledTime = %s,
ScaleInTime = %s,
SampleToLabTime = %s,
ScaleWeight = '%s',
SealTop = '%s',
SealBottom = '%s'
WHERE
pkRecvLogID = '%s';";
$values = [
($ScheduledTime == '') ? NULL : "'" . $ScheduledTime . "'",
($ScaleInTime == '') ? NULL : "'" . $ScaleInTime . "'",
($SampleToLabTime = '') ? NULL : "'" . $SampleToLabTime . "'",
$ScaleWeight,
$SealTop,
$SealBottom,
$pkRecvLogID,
];
$sql = vsprintf($query, $values);
Another variant:
$vars = array(
"ScheduledTime" => $ScheduledTime,
"ScaleInTime" => $ScaleInTime,
"SampleToLabTime" => $SampleToLabTime,
"ScaleWeight" => $ScaleWeight
"SealTop" => $SealTop,
"SealBottom" => $SealBottom
);
$set = array();
foreach($vars as $k => $v)
{
if ($v == '' || is_null($v))
{
$set[] = sprintf("`%s` = NULL", $k);
} else {
$set[] = sprintf("`%s` = '%s'", $k, $v);
}
}
$set = implode(', ', $set);
if ($set != "")
{
$sql = sprintf("UPDATE `tblRecvLog` SET %s WHERE `pkRecvLogID` = '%s'", $set, $pkRecvLogID);
...
}
I have this HTML form which has so many fields that someone can use to query data from MySQL table using multiple conditions. The form has select boxes, text boxes and check boxes, and date inputs.
I have this function which is ineffective
public function search(Request $request)
{
// loop through the defined fields
foreach($this->fields as $field){
// if the field is set and not empty
if(is_array($request->get($field))){
foreach ($request->get($field) as $value) {
$this->conditions[] = "`$field` = '" . $value . "'";
}
} else {
if(isset($_POST[$field]) && $request->get($field) != '') {
$data = $request->get($field);
if($field == 'bf_ref_no'){
$data = is_numeric( substr($request->get($field), 0, 2) ) ? 'BF'.$request->get($field) : $request->get($field) ;
}
$this->conditions[] = "`$field` = '" . $data . "'";
}
}
}
// builds the query
$query = "SELECT invoices.id as inv_id, invoices.created_at as inv_date, invoices.amount_paid, invoices.amount, csv_data_final.* FROM csv_data_final
LEFT JOIN invoices ON invoices.parent_id = csv_data_final.id ";
// if there are conditions defined
if(count($this->conditions) > 0) {
// append the conditions
$query .= "WHERE " . implode (' AND ', $this->conditions); // you can change to 'OR', but I suggest to apply the filters cumulative
}
$results = DB::select( $query );
$borders = DB::table('borders')->orderBy('id', 'DESC')->get();
return view('track.track-withdata', compact('results', 'borders'));
}
This code doesn't work for dates using BETWEEN keyword.
I'm using the last version of ADOdb PHP (5.18) to make some queries in a SQL Server database.
I select data in this way:
$rS = $localDb->Execute($sql);
if (!$rS) {
echo "Error: " . $localDb->ErrorMsg() . "\n";
}
else {
$tot = $rS->RecordCount();
echo " " . $tot . " record da inserire...\n";
while (!$rS->EOF) {
$id = $rS->fields['id'];
$field1 = $rS->fields['field1'];
$field2 = $rS->fields['field2'];
$rS->MoveNext();
}
}
All works, and I fetch data, but when a field in the database's current row is NULL, the relative element in $rS->fields has the value of the value of the last not-NULL row for the same field.
This is a big problem because I don't have correct data in the current row.
I tried search for this problem but I did not find any solution.
Coud you help me, please?
Look into adodb5/adodb.inc.php and find the GetRowAssoc function. It should be the following defintion:
function GetRowAssoc($upper=ADODB_ASSOC_CASE_UPPER)
{
$record = array();
if (!$this->bind) {
$this->GetAssocKeys($upper);
}
foreach($this->bind as $k => $v) {
if( array_key_exists( $v, $this->fields ) ) {
$record[$k] = $this->fields[$v];
} elseif( array_key_exists( $k, $this->fields ) ) {
$record[$k] = $this->fields[$k];
} else {
# This should not happen... trigger error ?
$record[$k] = null;
}
}
return $record;
}
Problem:
I am trying to delete all sublevels of a category by using a class. Currently I can only make it delete two sublevels, not three.
The database table:
CREATE TABLE betyg_category (
CID int(11) NOT NULL AUTO_INCREMENT,
Item varchar(100) NOT NULL,
Parent int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (CID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
The PHP class:
<?php
class ItemTree
{
var $itemlist = array();
function ItemTree($query)
{
$result = mysql_query($query) or die ('Database Error (' . mysql_errno() . ') ' . mysql_error());
while ($row = mysql_fetch_assoc($result))
{
$this->itemlist[$row['CID']] = array(
'name' => $row['Name'],
'parent' => $row['Parent']
);
}
}
function get_tree($parent, $with_parent=0)
{
$item_tree = array();
if ($with_parent == 1 && $parent != 0)
{
$item_tree[$parent]['name'] = $this->itemlist[$parent]['name'];
$item_tree[$parent]['parent'] = $this->itemlist[$parent]['parent'];
$item_tree[$parent]['child'] = $this->get_tree($parent);
return $item_tree;
}
foreach ($this->itemlist as $key => $val)
{
if ($val['parent'] == $parent)
{
$item_tree[$key]['name'] = $val['name'];
$item_tree[$key]['parent'] = $val['parent'];
$item_tree[$key]['child'] = $this->get_tree($key);
}
}
return $item_tree;
}
function make_optionlist ($id, $class='', $delimiter='/')
{
$option_list = '';
$item_tree = $this->get_tree(0);
$options = $this->make_options($item_tree, '', $delimiter);
if (!is_array($id))
{
$id = array($id);
}
foreach($options as $row)
{
list($index, $text) = $row;
$selected = in_array($index, $id) ? ' selected="selected"' : '';
$option_list .= "<option value=\"$index\" class=\"$class\"$selected>$text</option>\n";
}
return $option_list;
}
function make_options ($item_tree, $before, $delimiter='/')
{
$before .= empty($before) ? '' : $delimiter;
$options = array();
foreach ($item_tree as $key => $val)
{
$options[] = array($key, '- '.$before.$val['name']);
if (!empty($val['child'])) {
$options = array_merge($options, $this->make_options($val['child'], $before.$val['name'], $delimiter));
}
}
return $options;
}
function get_navlinks ($navid, $tpl, $startlink='', $delimiter=' ยป ')
{
// $tpl typ: {name}
$search = array('{id}', '{name}');
$navlink = array();
while (isset($this->itemlist[$navid]))
{
$replace = array($navid, $this->itemlist[$navid]['name']);
$navlink[] = str_replace($search, $replace, $tpl);
$navid = $this->itemlist[$navid]['parent'];
}
if (!empty($startlink))
{
$navlink[] = str_replace($search, array(0, $startlink), $tpl);
}
$navlink = array_reverse($navlink);
return implode($delimiter, $navlink);
}
function show_tree ($parent=0, $tpl='%s', $ul_class='', $li_class='')
{
$item_tree = $this->get_tree($parent);
return $this->get_node($item_tree, $parent, $tpl, $ul_class, $li_class);
}
function get_node ($item_tree, $parent, $tpl, $ul_class, $li_class)
{
// $tpl typ: {name}
$search = array('{id}', '{name}');
$output = "\n<ul class=\"$ul_class\">\n";
foreach ($item_tree as $id => $item)
{
$replace = array($id, $item['name']);
$output .= "<li class=\"$li_class\">".str_replace($search, $replace, $tpl);
$output .= !empty($item['child']) ? "<br />".$this->get_node ($item['child'], $id, $tpl, $ul_class, $li_class) : '';
$output .= "</li>\n";
}
return $output . "</ul>\n";
}
function get_id_in_node ($id)
{
$id_list = array($id);
if (isset($this->itemlist[$id]))
{
foreach ($this->itemlist as $key => $row)
{
if ($row['parent'] == $id)
{
if (!empty($row['child']))
{
$id_list = array_merge($id_list, get_id_in_node($key));
} else
{
$id_list[] = $key;
}
}
}
}
return $id_list;
}
function get_parent ($id)
{
return isset($this->itemlist[$id]) ? $this->itemlist[$id]['parent'] : false;
}
function get_item_name ($id)
{
return isset($this->itemlist[$id]) ? $this->itemlist[$id]['name'] : false;
}
}
?>
Scenario:
Say you have the following structure in a :
Literature
-- Integration of sources
---- Test 1
It will result in the following in the database table:
When I try to delete this sublevel, it will leave the last sublevel in the database while it should delete it. The result will be:
The PHP code:
//Check if delete button is set
if (isset($_POST['submit-deletecategory']))
{
//Get $_POST variables for category id
$CategoryParent = intval($_POST['CategoryList']);
//Check if category is selected
if ($CategoryParent != "#")
{
//Get parent category and subsequent child categories
$query = "SELECT CID, Item AS Name, Parent FROM " . TB_CATEGORY . " ORDER BY Name";
$items = new ItemTree($query);
if ($items->get_item_name($_POST['CategoryList']) !== false)
{
//Build up erase list
$CategoryErase = $items->get_id_in_node($CategoryParent);
$CategoryEraseList = implode(", ", $CategoryErase);
}
else
{
$CategoryEraseList = 0;
}
//Remove categories from database
$query = "DELETE FROM " . TB_CATEGORY . " WHERE CID IN ($CategoryEraseList)";
$result = mysql_query($query) or die ('Database Error (' . mysql_errno() . ') ' . mysql_error());
//Return a confirmation notice
header("Location: settings.php");
exit;
}
}
Thank you in advance for any guidance I can get to solve the issue.
Here is a way to do it : use a recursive function, which will first look for the leaf item (the deepest in your tree). You remove children first, then the parent. And for each child, you remove child's children first, etc...
deleteSub(1);
function deleteSub($cat_id) {
$request = "SELECT * FROM ". TB_CATEGORY ." WHERE Parent = ".$cat_id;
$results = mysql_query($request);
while($child = mysql_fetch_array($results))
{
deleteSub($child["CID"]);
}
$request = "DELETE FROM ". TB_CATEGORY ." WHERE CID = ".$cat_id;
return mysql_query($request);
}
A better way could be use this kind of recursive function to store CIDs in an array, then make a single DELETE request, but I think you'll be able to adapt this code.
I'm not going to read or try to understand the entire code, but it seems to me you need some sort of recursion function. What I basicly would do is create a function that goes up in the hierachy and one that goes down.
Note: It has been a while since i've written anything in procedural mysql, so please check if the mysql_num_rows(),mysql_fetch_array and so on is written in the correct manner
EDIT: I've just noticed you only wanted a downwards deletion and therefore zessx's answer is more valid
<?php
function recursiveParent($id) {
$sql = 'SELECT parent FROM betyg_category WHERE CID=' . $id;
$result = mysql_query($sql);
if(mysql_num_rows($result) > 0) {
while($r = mysql_fetch_array($result,MYSQLI_ASSOC)) {
recursiveParent($r['parent']);
}
}
$sql = 'DELETE FROM betyg_category WHERE CID=' . $id;
mysql_query($sql);
}
function recursiveChild($parent) {
$sql = 'SELECT CID FROM betyg_category WHERE parent=' . $parent;
$result = mysql_query($sql);
if(mysql_num_rows($result) > 0) {
while($r = mysql_fetch_array($result,MYSQLI_ASSOC)) {
recursiveChild($r['CID']);
}
}
$sql = 'DELETE FROM betyg_category WHERE parent=' . $parent;
mysql_query($sql);
}
function delete($id) {
recursiveParent($id);
recursiveChild($id);
}
?>
This is my way to do. instead of recursive the query to run, i get all the child's id first then only run query. here the code refer:-
First, defined a variable called $delete_node_list as array. (to store all node id that need to be delete)
function delete_child_nodes($node_id)
{
$childs_node = $this->edirectory_model->get_child_nodes($node_id);
if(!empty($childs_node))
{
foreach($childs_node as $node)
{
$this->delete_child_nodes($node['id']);
}
}
$this->delete_node_list[] = $node_id;
}
in mysql..
$sql = 'DELETE FROM betyg_category WHERE CID IN '.$this->delete_node_list;
mysql_query($sql);