I am new to json, my aim is to maintain the history of specific columns(which are posted through $_POST in php) on every update in mysql using php. I took one json array for the history column and placed it in a while loop, after that I appended the variable which i want to merge with the previous one with array_merge() function. I am getting the output but starting with 0. Let me know how to append the required fields in a proper json format and also how to retrieve the json data in a div tag. Thanks in advance.
PHP Code:
<?php
$query = mysqli_query($conn,"SELECT `history` FROM projects WHERE `no` = '$id'");
$json_data = array();
while ($js = mysqli_fetch_assoc($query))
{
$json_data[] = $js['history'];
$j = $json_data;
}
?>
<?php
if(isset($_POST['submit'])){
if(isset($_GET['id'])){
$id = $_GET['id'];
$assign = mysqli_real_escape_string($conn,$_POST['assign']);
$end_date = mysqli_real_escape_string($conn,$_POST['end_date']);
$comments = mysqli_real_escape_string($conn,$_POST['comments']);
$end_date = [
'assigned_to' => $assign,
'end_date' => $end_date,
'comments' => $comments
];
$json = array_merge($j,$end_date);
$js = json_encode($json);
$ins = mysqli_query($conn,"UPDATE `projects` SET `assigned_to`='$assign',`end_date`='$end_date',
`status`='$status',`comments`='$comments'`history`= '$js' WHERE
`episode_no` = '$id'");
}
}
?>
JSON data in MYSQL :
{"0":"{"0":"{"0":"","assigned_to":"AAA","end_date":"2018-09-12","comments":"happy"}",
"assigned_to":"AAA","end_date":"2018-09-12","comments":"jolly"}",
"assigned_to":"AAA","end_date":"2018-09-12","comments":"xvbcvbdfghdfg"}
First of all, the answer to your question: you are loading an array of strings in $j, so the array_merge function won't work as expected:
$j[0] = 'some JSON string from DB';
$json = array_merge($j, $end_date);
the array_merge finds that the second argument is a sparse array, so it merges the keys as strings:
$json = [
'0' => 'the previous string',
'assigned_to' => ...
]
For your idea to work you probably need to store the new history item by appending to the array:
$j[] = $end_date;
$js = json_encode($j);
...
This would solve your issue.
But there is a very major issue here that you need to solve first. It's a OMG-like WTF-like issue. You are getting $id from user input (query parameters) and sending it to the DB without any fear. Suppose that the user sends
https://your.server/some/path?id=';TRUNCATE TABLE projects --'
(propery url-encoded of course). Now you are sending this to the database:
SELECT `history` FROM projects WHERE `no` = '';TRUNCATE TABLE projects --''
Bye bye projects. A user can do whatever to your database, change passwords, reassign foreign keys, set himself as administrator.
Please for the sake of whatever you believe in, use a proper ORM and never pass user input to the DB!!!
Related
I am getting data from database in PhP array data_areas like this:
$query_area = "SELECT name FROM area where id>0";
$result = pg_query($con, $query_area) or die("Cannot execute query: $query_area\n");
if(pg_num_rows($result))
{
$data_areas=array();
while($row=pg_fetch_row($result))
{
$data_areas[] = array(
'name'=>$row[0]
);
}
pg_free_result($result);
pg_close($con);
$area1=$data_areas[0];
$area2=$data_areas[1];
}
How to retrieve the element from array in different variables, for example, I tried to retrieve data in area1 and area2 variable. Thank you
you can write like this;
$data_areas[0]['name']
Try Below code
$query_area = "SELECT name FROM area where id>0";
$result = pg_query($con, $query_area) or die("Cannot execute query: $query_area\n");
if(pg_num_rows($result))
{
$data_areas=array();
while($row=pg_fetch_row($result))
{
$data_areas[] = array(
'name'=>$row[0]
);
}
pg_free_result($result);
pg_close($con);
$area1=isset($data_areas[0]['name']) ?$data_areas[0]['name'] : '' ;
$area2= isset($data_areas[1]['name']) ? $data_areas[1]['name'] : '';
}
So first things first. You need first of all set up your array that you retrieve your data from the db.
Inside your while loop , and considering that you know what each of the rows has as associated value you can do something like:
$data_areas[] = array(
'name' => $row[0],
'surname' => $row[1],
'email' => $row[2]
);
This will create your array with all the values.
Now if you want to access/assign it's of those array values i am pretty sure you will need new dedicated arrays as your query retrieves all data from the table (small note that you don't need where id>0 as your id is auto increment so it will always be greater than 0)
Having said that we can move forward.
In order to access this data you can simple try:
print_r($data_areas['name']);
This will return you an array of all the names you have. So you don't need new table you can use the already existing one you have.
You are writing like this
$row[0]
Try writing this
$row['name']
I know how to get a mysql-row and convert it to json:
$row = mysqli_fetch_assoc(mysqli_query($db, "SELECT * FROM table WHERE id=1"));
echo json_encode($row); // it's an ajax-call
but:
the db-row has different types like int, float, string.
by converting it using json_encode() all results are strings.
Is there a better way to correct the types than this:
$row['floatvalue1'] = 0+$row['floatvalue1'];
$row['floatvalue2'] = 0+$row['floatvalue2'];
$row['intvalue1'] = 0+$row['intvalue1'];
I would like to loop through the keys and add 0 because:
first coding rule: DRY - dont repeat yourself
but i can't because:
row has also other types than numbers (string, date)
there are many columns
design is in dev, so columns-names often changes
Thanks in advance and excuse my bad english :-)
EDIT (to answer the comment-question from Casimir et Hippolyte):
I call this php-code using ajax to get dynamically sql-values. in my javascript-code i use the results like this:
result['intvalue1'] += 100;
lets say the json-result of intval1 is 50, the calculated result is:
"50100", not 150
The code below is just a proof of concept. It needs encapsulation in a function/method and some polishing before using it in production (f.e. call mysqli_fetch_field() in a loop and store the objects it returns before processing any row, not once for every row).
It uses the function mysqli_fetch_field() to get information about each column of the result set and converts to numbers those columns that have numeric types. The values of MYSQLI_TYPE_* constants can be found in the documentation page of Mysqli predefined constants.
// Get the data
$result = mysqli_query($db, "SELECT * FROM table WHERE id=1");
$row = mysqli_fetch_assoc($result);
// Fix the types
$fixed = array();
foreach ($row as $key => $value) {
$info = mysqli_fetch_field($result);
if (in_array($info->type, array(
MYSQLI_TYPE_TINY, MYSQLI_TYPE_SHORT, MYSQLI_TYPE_INT24,
MYSQLI_TYPE_LONG, MYSQLI_TYPE_LONGLONG,
MYSQLI_TYPE_DECIMAL,
MYSQLI_TYPE_FLOAT, MYSQLI_TYPE_DOUBLE
))) {
$fixed[$key] = 0 + $value;
} else {
$fixed[$key] = $value;
}
}
// Compare the results
echo('all strings: '.json_encode($row)."\n");
echo('fixed types: '.json_encode($fixed)."\n");
something like
$row['floatvalue1'] = reset( sscanf ( $row['floatvalue1'] , "%f" ));
$row['floatvalue2'] = reset( sscanf ( $row['floatvalue2'] , "%f" ));
$row['intvalue1'] = reset( sscanf ( $row['intvalue1'] , "%d" ));
json_encode($row);
If you're simply trying to make sure that your values are operable with respect to their type, you need to first cast their type correctly.
Unless you need them server-side, I would just pass-on the json directly to the front-end and do the work there.
In Javascript, you could make an attempt at casting the numbers like so:
function tryNumber(string){
return !isNaN( parseInt(string) ) ? parseInt(string) : string;
}
function tryDate(string){
return !isNaN( new Date(string).getTime() ) ? new Date(string) : string;
}
tryNumber('foo'); // "hello"
tryNumber('24'); // 24
tryDate('bar'); // "bar"
tryDate('December 17, 1995'); // "Sun Dec 17 1995 00:00:00 GMT+0000 (GMT)"
These two lines attempt to cast the values as a Date/Number. If they can't be cast, they will remain String's.
A MySQLi OO version based on #axiac's answer, that produces a JSON array ($jsnAll) containing all records. In this code snippet, the method FixSQLType is called to fix a row. Note, it should be wrapped in a try{}catch{} block and "objMySQLi" has already been instantiated:
$lcAllRows = array();
// Make an SQL SELECT statement
$SQL = "SELECT * FROM $lcName WHERE $lcWhere";
// Run the query
$this->sqlResult = $this->objMySQLi->query($SQL);
// Fetch the result
while( $row = $this->sqlResult->fetch_assoc()){
$lcCount = count($lcAllRows) ;
// Call to fix, row
$fixedRow = $this->FixSQLType($row);
$lcAllRows[$lcCount]= $fixedRow;
}
$jsnAll = json_encode($lcAllRows);
The FixSQLType method. This is almost identical to #axiac's answer, except for the call to $this->sqlResult->fetch_field_direct($i). "fetch_field" seemed to get itself lost, using "fetch_field_direct" overcame that problem.
private function FixSQLType($pRow){
// FROM https://stackoverflow.com/a/28261996/7571029
// Fix the types
$fixed = array();
$i = 0;
foreach ($pRow as $key => $value) {
$info = $this->sqlResult->fetch_field_direct($i);
$i++;
if (in_array($info->type, array(
MYSQLI_TYPE_TINY, MYSQLI_TYPE_SHORT, MYSQLI_TYPE_INT24,
MYSQLI_TYPE_LONG, MYSQLI_TYPE_LONGLONG,
MYSQLI_TYPE_DECIMAL,
MYSQLI_TYPE_FLOAT, MYSQLI_TYPE_DOUBLE
))) {
$fixed[$key] = 0 + $value;
} else {
$fixed[$key] = $value;
}
}
return $fixed;
}
I'm trying to set up some simple Amcharts graphs for a company intranet webpage. Over the last two weeks I have created HTML/JS and produced a nice graphic using Amcharts (data hard-coded in the HTML for demo purposes). I also installed XAMPP and created a MySQL database, populated with tables and some data that gets imported from csv files.
So far, everything is working fine - I can display nice graphics and I can collect the data for supplying data to the graphs. However, I have been approaching this problem from the 2 ends (getting the source data into a database AND presenting the data in a graph on a webpage). Now I need to join these 2 ends, so I can feed Amcharts with data from MySQL.
I know I need to use PHP to get the data from MySQL and put this into an array that can be used by Amcharts but my PHP knowledge is very basic and I'm struggling with the code.
What I have is PHP code which successfully connects to MySQL and extracts data to display in a browser - that works. I just don't know how to get that data into a multi-dimensional array in the format that Amcharts needs for plotting its graph.
It would be really great if you guys could give me some help here and fill in the missing pieces. I have some pseudo code for the logic of creating the array as the basis for the 'real' php code.
This is the pseudo code for populating the array:
;charset=UTF-8', '', '', array(PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$stmt = $db->query("SELECT * FROM <mytable> WHERE <mycondition>");
$prevweek = "9999";
$headrowdone = 0;
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
if ($prevweek < $row['WeekNumber']) {
// New week so write out Category X Label ('Week') with the week number of the following data rows
chartData.push($DataRow);
$headrowdone = 0;
}
if (!$headrowdone) {
$DataRow = "Week: "+$row['WeekNumber'];
$headrowdone = 1;
}
// Write out the X-Axis Category value and the Y-Axis value
$DataRow = $DataRow+$row['XAxisCategory']+": "+$row['YAxisCategory'];
$prevweek = $row['WeekNumber'];
}
chartData.push($DataRow); ?>
The SQL table looks like:
CREATE TABLE ( WeekNumber varchar(4), XAxisCategory
varchar(50), YAxisValue integer );
and has data like: '1301','A',10 '1301','B',20 '1301','C',24
'1302','A',11 '1302','B',22 '1302','C',27 '1303','A',14 '1303','B',23
'1303','C',28 ...etc
The data array for amcharts needs to look like:
var chartData = [{ Week: "1301",
A: 10,
B: 20,
C: 24
}, {
Week: "1302",
A: 11,
B: 22,
C: 27
}, {
Week: "1303",
A: 14,
B: 23,
C: 28
....etc
}];
// This is spoofing your fetch via pdo
$rows [] = array('WeekNumber'=>1301, 'A'=>10);
$rows [] = array('WeekNumber'=>1301, 'B'=>20);
$rows [] = array('WeekNumber'=>1301, 'C'=>25);
$rows [] = array('WeekNumber'=>1302, 'A'=>12);
$rows [] = array('WeekNumber'=>1302, 'B'=>22);
$rows [] = array('WeekNumber'=>1302, 'C'=>27);
//var_dump($rows);
// set up some vars
$lastweek = '';
$ctr = 0;
$data = array();
// loop thru the vars, build another array
foreach( $rows as $row){
if($row['WeekNumber'] !== $lastweek){
$ctr++;
$data[$ctr] = array('Week'=>$row['WeekNumber']);
$lastweek= $row['WeekNumber'];
}
// this could be nicer, but for now will do
if( isset($row['A']) ) $data[$ctr]['A'] = $row['A'];
if( isset($row['B']) ) $data[$ctr]['B'] = $row['B'];
if( isset($row['C']) ) $data[$ctr]['C'] = $row['C'];
}
var_dump($data);
Then use json_encode() to get into the format you want.
This answer is a bit kludgy, but at least gets away from building strings to make json.
I have this piece of code that currently almost does what I need. It needs to select all records from a table and then format them ready for encoding to JSON. However, ONE record will have a "type" field set as "default". This record is placed first in the JSON file and formatted slightly different.
Currently this works prefectly if the record set to default is the last entry in the database table. But, if it isn't, then the formatting breaks when encoding to JSON.
Can anyone help suggest a fix that would force it to ignore where the default entry is, but retain the formatting?
// Get the data from the DB.
$query = 'SELECT type, headline, startDate, text, media, caption, credits FROM #__timeline_entries'.$table.'';
$db->setQuery($query);
// Load it and put it into an array
$list = $db->loadObjectList();
$len = count($list);
$data = array();
for ($i = 0; $i < $len; $i++) {
$temp = (array) $list[$i];
$temp["asset"] = array(
"media" => $temp["media"],
"credit" => $temp["credits"],
"caption" => $temp["caption"]
);
unset($temp["media"]);
unset($temp["credits"]);
unset($temp["caption"]);
if ($temp["type"] == "default") {
$data = $list[$i];
unset($list[$i]);
$list[$i] = $temp;
}
}
// Prep it for JSON
$data->date = &$list;
// Loop it once more!
$dataTwo->timeline = &$data;
// Encode the data to JSON.
$jsondata = json_encode($dataTwo);
This is part of a Joomla component, but it doesn't really use any of the Joomla framework beyond the database connection. I thought I'd mention it just in case it made any difference, though I don't see how.
Add an ORDER BY clause:
ORDER by (type = "default")
This will be 0 for all the records except the default, which is 1, so it will be put last.
Add a WHERE clause to your MySQL statement:
$query = 'SELECT type, headline, startDate, text, media, caption, credits FROM #__timeline_entries'.$table.' WHERE type <> default';
I have the array $student[]
<?php
$student['id'] = "10402";
$student['hnumber'] = "H030502";
$student['name'] = "Larry Wayne";
print_r($student);
?>
It prints out:
Array ( [id] => 10402 [hnumber] => H030502 [name] => Larry Wayne )
What I want to accomplish is storing values into an array, that will then be inserted into a database table.
So the insert statement would be:
$q = "insert into table (id, hnumber, name) VALUES ('10401', 'H030502', 'Larry Wayne')";
I want to use an array to store all the values into it, labeling each value by their table field name, because it will be about 25 fields I will be inserting data into.
If there is a better way of accomplishing that, I am all ears.
Thanks in advance.
Assuming you are building an array of students from another source, how about something like this?
// data from an external source
$students = array(
// student 1
array(
123,
'h123',
'John Smith',
),
// student 2
array(
456,
'h456',
'Jane Smith',
),
// ... and so on
);
$values = array();
foreach ( $students as $student )
{
// #todo, make sure to sanitize values!!!
$values[] = sprintf('(%s)', implode(', ', $student));
}
// build query
$query = 'INSERT INTO `table` (`id`, `hnumber`, `name`) VALUES '.implode(', ', $values);
Please note, above code is "pseudo" or an idea if you want. Make sure to sanitize the values :)
EDIT: One more thing. Above code is good if you want a simple fix, preferably for some sort of simple data import. Better way is to create a class Student handling all this logic.
I wanted to simply comment on David's example as it's pretty much the same thing I was going to suggest, but I can't add code to comments, unfortunately. One thing David forgot from your original question was that you wanted to use the table fields as part of your array - in this example, as the key fields. In the foreach, you can split the array in to key/value pairs, and then use them later on in your code itself.
<?php
$student['id'] = "10402";
$student['hnumber'] = "H030502";
$student['name'] = "Larry Wayne";
$queryFields = array();
$queryValues = array();
$queryString = '';
foreach($student as $key => $value){
$queryFields[] = '`'.$key.'`';
$queryValues[] = $value;
}
$queryString = 'INSERT INTO `table` ('.implode(',', $queryFields).') VALUES ('.implode(',', $queryValues).')';
//run_query($queryString)
?>
Since I'm not 100% familiar with CodeIgniter, it's very possible that there might be a way to map arrays and/or objects to some sort of ActiveRecord implementation. However, since you're just looking for a way to generate a query string itself, this would do the trick.