How to properly format JSON - javascript

I asked a question earlier, which all revolved around a JSON formatting problem. I have a PHP page, which just grabs rows from a MYSQL database, and returns them. However, i'm unsure how to format them so all the columns I get are a set, and for each row, it creates a new set. I'm not sure what is common practice to do to encode things like this.
e.g. this is what I want (if it is even correct):
{ "message": [
{
"chat":"Hello, world!",
"time":"2014-05-09 17:32:00",
"username":"Josue"
},
{
"chat":"This is my second message.",
"time":"2014-05-09 17:32:05",
"username":"Josue"
}
]
}
That way, I can parse using $.parseAJAX, and get access to my data like: data.message[0].chat, and it would return "Hello world!".
Here is what I am currently doing:
$SQL = sprintf('SELECT time_sent, chat, username FROM Messages where time_sent >= date(\'%s\')', $last_chat_time);
$result = mysql_query($SQL);
$messages = Array();
while ( $row = mysql_fetch_assoc($result) ) {
$messages[] = 'chat';
$messages[] = $row['chat'];
$messages[] = 'time';
$messages[] = $row['time_sent'];
$messages[] = 'username';
$messages[] = $row['username'];
}
$loopCount = count($chats);
if(count($messages) > 0){
/*
$sexyJSON = '{message: [';
for($i = 0; $i < $loopCount; $i++){
$sexyJSON .= '{"chat":"'.$chats[$i].'","time":"'.$times[$i].'","username":"'.$usernames[$i].'"},';
}
$sexyJSON = substr($sexyJSON,0,strlen($sexyJSON)-1);
$sexyJSON .= ']}';
$newMessages = $sexyJSON;
echo $sexyJSON;
*/
echo json_encode($messages);
}
When I simply encode my array, it returns something like this:
["chat","Hello, world!","time","2014-05-09 17:32:00","username","Josue","chat","hmmm","time","2014-05-09 17:48:34","username","asdf"]
What would I have to do to group chat with the message, date with the date, and username with the username in a key-value pair?

The format of the mysql_fetch_assoc should be
array('chat'=>'Some chat', 'time_sent'=>'123456', 'username'=>'abcdefg')
json_encode would directly translate this to
{"chat":"Some chat", "time_sent":"123456", "username":"abcdefg"}
So in your loop, if you simply do $mesages[] = $row; and leave your json_encode call as-is, it should work as shown above. However, you can alter your SQL statement to give the columns an alias so that time_sent simply shows as the property time

This is what i would do:
$SQL = sprintf('SELECT time_sent, chat, username FROM Messages where time_sent >= date(\'%s\')', $last_chat_time);
$result = mysql_query($SQL);
$messages = array();
while ( $row = mysql_fetch_assoc($result) ) {
$arr = array();
$arr['chat'] = $row['chat'];
$arr['time'] = $row['time_sent'];
$arr['username'] = $row['username'];
$messages[] = $arr;
}
$loopCount = count($chats);
if(count($messages) > 0){
echo json_encode($messages);
}
This will output if not encoded:
Array
(
[0] => Array
(
[chat] => chat_0
[time] => time_sent_0
[username] => username_0
)
[1] => Array
(
[chat] => chat_1
[time] => time_sent_1
[username] => username_1
)
[2] => Array
(
[chat] => chat_2
[time] => time_sent_2
[username] => username_2
)
[3] => Array
(
[chat] => chat_3
[time] => time_sent_3
[username] => username_3
)
)
And this if encoded:
[{"chat":"chat_0","time":"time_sent_0","username":"username_0"},
{"chat":"chat_1","time":"time_sent_1","username":"username_1"},
{"chat":"chat_2","time":"time_sent_2","username":"username_2"},
{"chat":"chat_3","time":"time_sent_3","username":"username_3"}]
To parse the JSON
lets say you have your JSON results in a data var
var obj = $.parseJSON(data);
$.each(obj, function(i, value){
console.log(value.chat);
});

You need to work with multi-dimensional arrays in order to get this to work. The code below has been edited to assign values to named indexes and append these to the 2nd level to the $messages array.
$messages = Array();
while ( $row = mysql_fetch_assoc($result) ) {
$messages[] = Array(
'chat' => $row['chat'],
'time' => $row['time_sent'],
'username' => $row['username']
);
}

The while cycle should be like this:
while ( $row = mysql_fetch_assoc($result) ) {
$arr = array();
$arr['chat'] = $row['chat'];
$arr['time'] = $row['time_sent'];
$arr['username'] = $row['username'];
$messages[] = $arr;
}

Save a little time by getting the field names correct within the SQL.
$SQL = sprintf('SELECT time_sent as `time`, chat, username FROM Messages where time_sent >= date(\'%s\')', $last_chat_time);
$result = mysql_query($SQL);
$messages = array();
while ($row = mysql_fetch_assoc($result)) {
$messages[] = $row;
}
echo json_encode($messages);
IMO returning an empty array when there are no messages is better than returning nothing, as now you have a way to differentiate if your php worked vs if you had no messages, from within your JavaScript code.

Related

Problem with server side filtering data with php [duplicate]

I'm curious to know if it's possible to bind an array of values to a placeholder using PDO. The use case here is attempting to pass an array of values for use with an IN() condition.
I'd like to be able to do something like this:
<?php
$ids=array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
'SELECT *
FROM table
WHERE id IN(:an_array)'
);
$stmt->bindParam('an_array',$ids);
$stmt->execute();
?>
And have PDO bind and quote all the values in the array.
At the moment I'm doing:
<?php
$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
foreach($ids as &$val)
$val=$db->quote($val); //iterate through array and quote
$in = implode(',',$ids); //create comma separated list
$stmt = $db->prepare(
'SELECT *
FROM table
WHERE id IN('.$in.')'
);
$stmt->execute();
?>
Which certainly does the job, but just wondering if there's a built in solution I'm missing?
You'll have to construct the query-string.
<?php
$ids = array(1, 2, 3, 7, 8, 9);
$inQuery = implode(',', array_fill(0, count($ids), '?'));
$db = new PDO(...);
$stmt = $db->prepare(
'SELECT *
FROM table
WHERE id IN(' . $inQuery . ')'
);
// bindvalue is 1-indexed, so $k+1
foreach ($ids as $k => $id)
$stmt->bindValue(($k+1), $id);
$stmt->execute();
?>
Both chris (comments) and somebodyisintrouble suggested that the foreach-loop ...
(...)
// bindvalue is 1-indexed, so $k+1
foreach ($ids as $k => $id)
$stmt->bindValue(($k+1), $id);
$stmt->execute();
... might be redundant, so the foreach loop and the $stmt->execute could be replaced by just ...
<?php
(...)
$stmt->execute($ids);
For something quick:
//$db = new PDO(...);
//$ids = array(...);
$qMarks = str_repeat('?,', count($ids) - 1) . '?';
$sth = $db->prepare("SELECT * FROM myTable WHERE id IN ($qMarks)");
$sth->execute($ids);
Is it so important to use IN statement? Try to use FIND_IN_SET op.
For example, there is a query in PDO like that
SELECT * FROM table WHERE FIND_IN_SET(id, :array)
Then you only need to bind an array of values, imploded with comma, like this one
$ids_string = implode(',', $array_of_smth); // WITHOUT WHITESPACES BEFORE AND AFTER THE COMMA
$stmt->bindParam('array', $ids_string);
and it's done.
UPD: As some people pointed out in comments to this answer, there are some issues which should be stated explciitly.
FIND_IN_SET doesn't use index in a table, and it is still not implemented yet - see this record in the MYSQL bug tracker. Thanks to #BillKarwin for the notice.
You can't use a string with comma inside as a value of the array for search. It is impossible to parse such string in the right way after implode since you use comma symbol as a separator. Thanks to #VaL for the note.
In fine, if you are not heavily dependent on indexes and do not use strings with comma for search, my solution will be much easier, simpler, and faster than solutions listed above.
Since I do a lot of dynamic queries, this is a super simple helper function I made.
public static function bindParamArray($prefix, $values, &$bindArray)
{
$str = "";
foreach($values as $index => $value){
$str .= ":".$prefix.$index.",";
$bindArray[$prefix.$index] = $value;
}
return rtrim($str,",");
}
Use it like this:
$bindString = helper::bindParamArray("id", $_GET['ids'], $bindArray);
$userConditions .= " AND users.id IN($bindString)";
Returns a string :id1,:id2,:id3 and also updates your $bindArray of bindings that you will need when it's time to run your query. Easy!
very clean way for postgres is using the postgres-array ("{}"):
$ids = array(1,4,7,9,45);
$param = "{".implode(', ',$ids)."}";
$cmd = $db->prepare("SELECT * FROM table WHERE id = ANY (?)");
$result = $cmd->execute(array($param));
Solution from EvilRygy didn't worked for me. In Postgres you can do another workaround:
$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
'SELECT *
FROM table
WHERE id = ANY (string_to_array(:an_array, ','))'
);
$stmt->bindParam(':an_array', implode(',', $ids));
$stmt->execute();
Here is my solution:
$total_items = count($array_of_items);
$question_marks = array_fill(0, $total_items, '?');
$sql = 'SELECT * FROM foo WHERE bar IN (' . implode(',', $question_marks ). ')';
$stmt = $dbh->prepare($sql);
$stmt->execute(array_values($array_of_items));
Note the use of array_values. This can fix key ordering issues.
I was merging arrays of ids and then removing duplicate items. I had something like:
$ids = array(0 => 23, 1 => 47, 3 => 17);
And that was failing.
Looking at PDO :Predefined Constants there is no PDO::PARAM_ARRAY which you would need as is listed on PDOStatement->bindParam
bool PDOStatement::bindParam ( mixed $parameter , mixed &$variable [, int $data_type [, int $length [, mixed $driver_options ]]] )
So I don't think it is achievable.
I extended PDO to do something similar to what stefs suggests, and it was easier for me in the long run:
class Array_Capable_PDO extends PDO {
/**
* Both prepare a statement and bind array values to it
* #param string $statement mysql query with colon-prefixed tokens
* #param array $arrays associatve array with string tokens as keys and integer-indexed data arrays as values
* #param array $driver_options see php documention
* #return PDOStatement with given array values already bound
*/
public function prepare_with_arrays($statement, array $arrays, $driver_options = array()) {
$replace_strings = array();
$x = 0;
foreach($arrays as $token => $data) {
// just for testing...
//// tokens should be legit
//assert('is_string($token)');
//assert('$token !== ""');
//// a given token shouldn't appear more than once in the query
//assert('substr_count($statement, $token) === 1');
//// there should be an array of values for each token
//assert('is_array($data)');
//// empty data arrays aren't okay, they're a SQL syntax error
//assert('count($data) > 0');
// replace array tokens with a list of value tokens
$replace_string_pieces = array();
foreach($data as $y => $value) {
//// the data arrays have to be integer-indexed
//assert('is_int($y)');
$replace_string_pieces[] = ":{$x}_{$y}";
}
$replace_strings[] = '('.implode(', ', $replace_string_pieces).')';
$x++;
}
$statement = str_replace(array_keys($arrays), $replace_strings, $statement);
$prepared_statement = $this->prepare($statement, $driver_options);
// bind values to the value tokens
$x = 0;
foreach($arrays as $token => $data) {
foreach($data as $y => $value) {
$prepared_statement->bindValue(":{$x}_{$y}", $value);
}
$x++;
}
return $prepared_statement;
}
}
You can use it like this:
$db_link = new Array_Capable_PDO($dsn, $username, $password);
$query = '
SELECT *
FROM test
WHERE field1 IN :array1
OR field2 IN :array2
OR field3 = :value
';
$pdo_query = $db_link->prepare_with_arrays(
$query,
array(
':array1' => array(1,2,3),
':array2' => array(7,8,9)
)
);
$pdo_query->bindValue(':value', '10');
$pdo_query->execute();
When you have other parameter, you may do like this:
$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
$query = 'SELECT *
FROM table
WHERE X = :x
AND id IN(';
$comma = '';
for($i=0; $i<count($ids); $i++){
$query .= $comma.':p'.$i; // :p0, :p1, ...
$comma = ',';
}
$query .= ')';
$stmt = $db->prepare($query);
$stmt->bindValue(':x', 123); // some value
for($i=0; $i<count($ids); $i++){
$stmt->bindValue(':p'.$i, $ids[$i]);
}
$stmt->execute();
For me the sexier solution is to construct a dynamic associative array & use it
// A dirty array sent by user
$dirtyArray = ['Cecile', 'Gilles', 'Andre', 'Claude'];
// we construct an associative array like this
// [ ':name_0' => 'Cecile', ... , ':name_3' => 'Claude' ]
$params = array_combine(
array_map(
// construct param name according to array index
function ($v) {return ":name_{$v}";},
// get values of users
array_keys($dirtyArray)
),
$dirtyArray
);
// construct the query like `.. WHERE name IN ( :name_1, .. , :name_3 )`
$query = "SELECT * FROM user WHERE name IN( " . implode(",", array_keys($params)) . " )";
// here we go
$stmt = $db->prepare($query);
$stmt->execute($params);
I had a unique problem where, while converting the soon-to-be deprecated MySQL driver to the PDO driver I had to make a function which could build, dynamically, both normal parameters and INs from the same parameter array. So I quickly built this:
/**
* mysql::pdo_query('SELECT * FROM TBL_WHOOP WHERE type_of_whoop IN :param AND siz_of_whoop = :size', array(':param' => array(1,2,3), ':size' => 3))
*
* #param $query
* #param $params
*/
function pdo_query($query, $params = array()){
if(!$query)
trigger_error('Could not query nothing');
// Lets get our IN fields first
$in_fields = array();
foreach($params as $field => $value){
if(is_array($value)){
for($i=0,$size=sizeof($value);$i<$size;$i++)
$in_array[] = $field.$i;
$query = str_replace($field, "(".implode(',', $in_array).")", $query); // Lets replace the position in the query string with the full version
$in_fields[$field] = $value; // Lets add this field to an array for use later
unset($params[$field]); // Lets unset so we don't bind the param later down the line
}
}
$query_obj = $this->pdo_link->prepare($query);
$query_obj->setFetchMode(PDO::FETCH_ASSOC);
// Now lets bind normal params.
foreach($params as $field => $value) $query_obj->bindValue($field, $value);
// Now lets bind the IN params
foreach($in_fields as $field => $value){
for($i=0,$size=sizeof($value);$i<$size;$i++)
$query_obj->bindValue($field.$i, $value[$i]); // Both the named param index and this index are based off the array index which has not changed...hopefully
}
$query_obj->execute();
if($query_obj->rowCount() <= 0)
return null;
return $query_obj;
}
It is still untested however the logic seems to be there.
After some testing, I found out:
PDO does not like '.' in their names (which is kinda stupid if you ask me)
bindParam is the wrong function, bindValue is the right function.
A little editing about the code of Schnalle
<?php
$ids = array(1, 2, 3, 7, 8, 9);
$inQuery = implode(',', array_fill(0, count($ids)-1, '?'));
$db = new PDO(...);
$stmt = $db->prepare(
'SELECT *
FROM table
WHERE id IN(' . $inQuery . ')'
);
foreach ($ids as $k => $id)
$stmt->bindValue(($k+1), $id);
$stmt->execute();
?>
//implode(',', array_fill(0, count($ids)-1), '?'));
//'?' this should be inside the array_fill
//$stmt->bindValue(($k+1), $in);
// instead of $in, it should be $id
What database are you using? In PostgreSQL I like using ANY(array). So to reuse your example:
<?php
$ids=array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
'SELECT *
FROM table
WHERE id = ANY (:an_array)'
);
$stmt->bindParam('an_array',$ids);
$stmt->execute();
?>
Unfortunately this is pretty non-portable.
On other databases you'll need to make up your own magic as others have been mentioning. You'll want to put that logic into a class/function to make it reusable throughout your program of course. Take a look at the comments on mysql_query page on PHP.NET for some more thoughts on the subject and examples of this scenario.
If the column can only contain integers, you could probably do this without placeholders and just put the ids in the query directly. You just have to cast all the values of the array to integers. Like this:
$listOfIds = implode(',',array_map('intval', $ids));
$stmt = $db->prepare(
"SELECT *
FROM table
WHERE id IN($listOfIds)"
);
$stmt->execute();
This shouldn't be vulnerable to any SQL injection.
As I know there is no any possibility to bind an array into PDO statement.
But exists 2 common solutions:
Use Positional Placeholders (?,?,?,?) or Named Placeholders (:id1, :id2, :id3)
$whereIn = implode(',', array_fill(0, count($ids), '?'));
Quote array earlier
$whereIn = array_map(array($db, 'quote'), $ids);
Both options are good and safe.
I prefer second one because it's shorter and I can var_dump parameters if I need it.
Using placeholders you must bind values and in the end your SQL code will be the same.
$sql = "SELECT * FROM table WHERE id IN ($whereIn)";
And the last and important for me is avoiding error "number of bound variables does not match number of tokens"
Doctrine it's great example of using positional placeholders, only because it has internal control over incoming parameters.
It's not possible to use an array like that in PDO.
You need to build a string with a parameter (or use ?) for each value, for instance:
:an_array_0, :an_array_1, :an_array_2, :an_array_3, :an_array_4, :an_array_5
Here's an example:
<?php
$ids = array(1,2,3,7,8,9);
$sqlAnArray = join(
', ',
array_map(
function($index) {
return ":an_array_$index";
},
array_keys($ids)
)
);
$db = new PDO(
'mysql:dbname=mydb;host=localhost',
'user',
'passwd'
);
$stmt = $db->prepare(
'SELECT *
FROM table
WHERE id IN('.$sqlAnArray.')'
);
foreach ($ids as $index => $id) {
$stmt->bindValue("an_array_$index", $id);
}
If you want to keep using bindParam, you may do this instead:
foreach ($ids as $index => $id) {
$stmt->bindParam("an_array_$index", $ids[$id]);
}
If you want to use ? placeholders, you may do it like this:
<?php
$ids = array(1,2,3,7,8,9);
$sqlAnArray = '?' . str_repeat(', ?', count($ids)-1);
$db = new PDO(
'mysql:dbname=dbname;host=localhost',
'user',
'passwd'
);
$stmt = $db->prepare(
'SELECT *
FROM phone_number_lookup
WHERE country_code IN('.$sqlAnArray.')'
);
$stmt->execute($ids);
If you don't know if $ids is empty, you should test it and handle that case accordingly (return an empty array, or return a Null Object, or throw an exception, ...).
After going through the same problem, i went to a simpler solution (although still not as elegant as an PDO::PARAM_ARRAY would be) :
given the array $ids = array(2, 4, 32):
$newparams = array();
foreach ($ids as $n => $val){ $newparams[] = ":id_$n"; }
try {
$stmt = $conn->prepare("DELETE FROM $table WHERE ($table.id IN (" . implode(", ",$newparams). "))");
foreach ($ids as $n => $val){
$stmt->bindParam(":id_$n", intval($val), PDO::PARAM_INT);
}
$stmt->execute();
... and so on
So if you are using a mixed values array, you will need more code to test your values before assigning the type param:
// inside second foreach..
$valuevar = (is_float($val) ? floatval($val) : is_int($val) ? intval($val) : is_string($val) ? strval($val) : $val );
$stmt->bindParam(":id_$n", $valuevar, (is_int($val) ? PDO::PARAM_INT : is_string($val) ? PDO::PARAM_STR : NULL ));
But i have not tested this one.
With MySQL and PDO we can use a JSON array and JSON_CONTAINS() (https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-contains) to search in.
$ids = [123, 234, 345, 456]; // Array of users I search
$ids = json_encode($ids); // JSON conversion
$sql = <<<SQL
SELECT ALL user_id, user_login
FROM users
-- Cast is mandatory beaucause JSON_CONTAINS() waits JSON doc candidate
WHERE JSON_CONTAINS(:ids, CAST(user_id AS JSON))
SQL;
$search = $pdo->prepare($sql);
$search->execute([':ids' => $ids]);
$users = $search->fetchAll();
Whe can also use JSON_TABLE() (https://dev.mysql.com/doc/refman/8.0/en/json-table-functions.html#function_json-table) for more complex cases and JSON data exploration :
$users = [
['id' => 123, 'bday' => ..., 'address' => ...],
['id' => 234, 'bday' => ..., 'address' => ...],
['id' => 345, 'bday' => ..., 'address' => ...],
]; // I'd like to know their login
$users = json_encode($users);
$sql = <<<SQL
SELECT ALL user_id, user_login
FROM users
WHERE user_id IN (
SELECT ALL user_id
FROM JSON_TABLE(:users, '$[*]' COLUMNS (
-- Data exploration...
-- (if needed I can explore really deeply with NESTED kword)
user_id INT PATH '$.id',
-- I could skip these :
user_bday DATE PATH '$.bday',
user_address TINYTEXT PATH '$.address'
)) AS _
)
SQL;
$search = $pdo->prepare($sql);
$search->execute([':users' => $users]);
...
Here is my solution, based on alan_mm's answer. I have also extended the PDO class:
class Db extends PDO
{
/**
* SELECT ... WHERE fieldName IN (:paramName) workaround
*
* #param array $array
* #param string $prefix
*
* #return string
*/
public function CreateArrayBindParamNames(array $array, $prefix = 'id_')
{
$newparams = [];
foreach ($array as $n => $val)
{
$newparams[] = ":".$prefix.$n;
}
return implode(", ", $newparams);
}
/**
* Bind every array element to the proper named parameter
*
* #param PDOStatement $stmt
* #param array $array
* #param string $prefix
*/
public function BindArrayParam(PDOStatement &$stmt, array $array, $prefix = 'id_')
{
foreach($array as $n => $val)
{
$val = intval($val);
$stmt -> bindParam(":".$prefix.$n, $val, PDO::PARAM_INT);
}
}
}
Here is a sample usage for the above code:
$idList = [1, 2, 3, 4];
$stmt = $this -> db -> prepare("
SELECT
`Name`
FROM
`User`
WHERE
(`ID` IN (".$this -> db -> CreateArrayBindParamNames($idList)."))");
$this -> db -> BindArrayParam($stmt, $idList);
$stmt -> execute();
foreach($stmt as $row)
{
echo $row['Name'];
}
you first set number of "?" in query and then by a "for" send parameters
like this :
require 'dbConnect.php';
$db=new dbConnect();
$array=[];
array_push($array,'value1');
array_push($array,'value2');
$query="SELECT * FROM sites WHERE kind IN (";
foreach ($array as $field){
$query.="?,";
}
$query=substr($query,0,strlen($query)-1);
$query.=")";
$tbl=$db->connection->prepare($query);
for($i=1;$i<=count($array);$i++)
$tbl->bindParam($i,$array[$i-1],PDO::PARAM_STR);
$tbl->execute();
$row=$tbl->fetchAll(PDO::FETCH_OBJ);
var_dump($row);
I took it a bit further to get the answer closer to the original question of using placeholders to bind the params.
This answer will have to make two loops through the array to be used in the query. But it does solve the issue of having other column placeholders for more selective queries.
//builds placeholders to insert in IN()
foreach($array as $key=>$value) {
$in_query = $in_query . ' :val_' . $key . ', ';
}
//gets rid of trailing comma and space
$in_query = substr($in_query, 0, -2);
$stmt = $db->prepare(
"SELECT *
WHERE id IN($in_query)";
//pind params for your placeholders.
foreach ($array as $key=>$value) {
$stmt->bindParam(":val_" . $key, $array[$key])
}
$stmt->execute();
You could convert this:
$stmt = $db->prepare('SELECT * FROM table WHERE id IN('.$in.')');
In this:
$stmt = $db->prepare('SELECT * FROM table WHERE id IN(:id1, :id2, :id3, :id7, :id8, :id9)');
And execute it with this array:
$stmt->execute(array(
:id1 =>1, :id2 =>2, :id3 =>3, :id7 =>7, :id8 =>8, :id9 => 9
)
);
Thus:
$in = array();
$consultaParam = array();
foreach($ids as $k => $v){
$in[] = ':id'.$v;
$consultaParam[':id'.$v] = $v;
}
Final code:
$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
$in = array();
$consultaParam = array();
foreach($ids as $k => $v){
$in[] = ':id'.$v;
$consultaParam[':id'.$v] = $v;
}
$stmt = $db->prepare(
'SELECT *
FROM table
WHERE id IN('.$in.')'
);
$stmt->execute($consultaParam);

How to parse a JSON data that has been received by a PHP scipt

I have sent data from my php script using `json_encode' function.
if I console.log(resp) below is the O/P I get.
data: "{"dept_name":"IT","city_name":"Mumbai","emp_id":"#AC001","emp_name":"Akshay S. Shrivastav"}
{"dept_name":"IT","city_name":"Mumbai","emp_id":"#AC003","emp_name":"Aakash Shrivastav"}" status: "success"
however, if I console.log(resp.data) I get the below data
{"dept_name":"IT","city_name":"Mumbai","emp_id":"#AC001","emp_name":"Akshay S. Shrivastav"}{"dept_name":"IT","city_name":"Mumbai","emp_id":"#AC003","emp_name":"Aakash Shrivastav"}
Now I'm trying to display this data in the data tables for which I am using the below code.
$('#grpList').DataTable().row.add([
resp.data.dept_name,
resp.data.city_name,
resp.data.emp_id,
resp.data.emp_name
]).draw(false);
I'm receiving the following error
DataTables warning: table id=grpList - Requested unknown parameter '0' for row 0, column 0. For more information about this error, please see http://datatables.net/tn/4
when I am single handed displaying only console.log(resp.data.dept_name) it says undefined
I'll be having multiple JSON response if the data increases, for now, I only have two. I'm not able to figure out how to display multiple data using a loop and appending it to the data table.
I'm using below php code to generate JSON
$jsonArray = "";
if($data->num_rows > 0)
{
while($row = $data->fetch_assoc())
{
$jsonArray .= json_encode(
array(
"dept_name" => $row['department_name'],
"city_name" => $row['city_name'],
"emp_id" => $row['emp_id'],
"emp_name" => $row['name']
));
}
echo json_encode(array("data" => $jsonArray, "status" => 'success'));
}
Because resp.data is an array of objects. You need to get the index first - let's say index 0, or the first object in the array:
$("#grpList").DataTable().row.add([
resp.data[0].dept_name,
resp.data[0].city_name,
resp.data[0].emp_id,
resp.data[0].emp_name
]).draw(false);
And if you want the second object:
$("#grpList").DataTable().row.add([
resp.data[1].dept_name,
resp.data[1].city_name,
resp.data[1].emp_id,
resp.data[1].emp_name
]).draw(false);
Of course, row.add() accepts an array argument as well - so this would work too:
$("#grpList").DataTable().row.add(resp.data).draw(false);
The issue is on server side.
You define $jsonArray as a string ! That's wrong.
Try this instead:
$jsonArray = []; // An ARRAY here!
if($data->num_rows > 0)
{
while($row = $data->fetch_assoc())
{
array_push($jsonArray, json_encode( // Use array_push here
array(
"dept_name" => $row['department_name'],
"city_name" => $row['city_name'],
"emp_id" => $row['emp_id'],
"emp_name" => $row['name']
));
}
echo json_encode(array("data" => $jsonArray, "status" => 'success'));
}
EDIT
I don't if the above works... Since I did not test it.
But here's how I would have writen it (I guess you'll have more chances with it):
$jsonArray = [];
if($data->num_rows > 0) {
while($row = $data->fetch_assoc()) {
// A temp array to rename the one of the keys...
$tempArray = [];
$tempArray = ["dept_name"] = $row['department_name'];
$tempArray = ["city_name"] = $row['city_name'];
$tempArray = ["emp_id"] = $row['emp_id'];
$tempArray = ["emp_name"] = $row['name'];
// Push to the jsonArray now...
array_push($jsonArray,$tempArray);
}
// And finally the result array... To be json encoded
$result = [];
$result = ["status"] = "success";
$result = ["data"] = jsonArray;
echo json_encode($result);
}
Note that without renaming one key and if there's only 4 data per rows from the DB... You could have done array_push($jsonArray,$row); directly, without using the $tempArray.
So try this... AND then apply Jack's answer. ;)

Cannot get value from Key JSON MySQL PHP

I am retrieving data from a MySQL database using PHP and attempting to use JSON.stringify and JSON.parse to create an object. It works fine but I cannot get the assocaited keys/values. Just the entire object. I break this up in to parts. Here is the PHP code:
First PHP File:
<?php
session_start();
include("web_db_operations.php");
if(isset($_POST['recipeId']) && isset($_SESSION['email'])){
$recipeId = $_POST['recipeId'];
$email = $_SESSION['email'];
}
else{
echo "Did not work";
}
$results = getAllMyRecipesAsList_recipeTable2($email, $recipeId);
$_SESSION['recipeResults'] = $results;
header('location:web_selected_recipe.php');
exit();
?>
Second PHP File
function getAllMyRecipesAsList_recipeTable2(string $email, int $recipeId){
include 'config.php';
$sql = 'SELECT * FROM recipeTable WHERE email = :email AND recipeId = :recipeId';
$stmt = $conn->prepare($sql);
$stmt->bindParam(':email', $email, PDO::PARAM_STR);
$stmt->bindParam(':recipeId', $recipeId, PDO::PARAM_STR);
$stmt->execute();
$getResults = $stmt->fetchAll(PDO::FETCH_ASSOC);
$json = array();
if(count($getResults) > 0){
foreach($getResults as $row){
$json[] = array('firstName' => $row['firstName'],
'lastName' => $row['lastName'],
'email' => $row['email'],
'recipeName' => $row['recipeName'],
'description' => $row['description'],
'ingredients' => $row['ingredients'],
'prepTime' => $row['prepTime'],
'steps' => $row['steps'],
'nutrition' => $row['nutrition'],
'servings' => $row['servings'],
'rating' => $row['rating'],
'tags' => $row['tags'],
'imagePath' => $row['imagePath'],
'imageName' => $row['imageName'],
'recipeId' => $row['recipeId']
);
}
$results = json_encode($json);
return $results;
}else{
echo "no data found";
}
}
Then to retrieve in my JS file (this is just the relevant parts):
<script>
<?php $results = $_SESSION['recipeResults'];
var results = <?php echo $results; ?>;
var toString = JSON.stringify(results);
console.log(toString);
var parsed = JSON.parse(toString);
console.log(parsed);
</script>
Logging resultAsString yields this:
[{"firstName":"Marcus","lastName":"Holden","email":"marcus#gmail.com","recipeName":"Aloo Paratha","description":"","ingredients":"","prepTime":"25 Minutes","steps":"","nutrition":"","servings":"","rating":"","tags":"","imagePath":"../userRecipeImages","imageName":"9110164.jpg","recipeId":"1"}]
Logging parsed yields this:
[{…}]
0:description:
"No Description", email "marcus#gmail.com", firstName:"Marcus", imageName:"9110164.jpg", imagePath:"../userRecipeImages", ingredients:"Some Ingredients",lastName:"Holden", nutrition:"Not given", prepTime:"25 Minutes", rating:"5/10", recipeId:"1", recipeName:"Aloo Paratha", servings: "6", steps:"Your Steps Here", tags:"It's bread"
Now, I have tried all steps to get the value associated with a key... for instance my object here is called parsed... so I have tried parsed.firstName.. returns undefined... as well as Object.keys(parsed). I cannot seem to get the keys. I would like to work with it like an array... setting content like this:
element.innerHTML = parsed[2]... etc.
What am I missing here?
I think you're doing quite a bit more than you need to. The data is coming to you as a JSON-encoded object. Just work with it.
<script>
var results = <?php echo $_SESSION['recipeResults']; ?>;
var first_results = results[0]; // Each array member is one object from your result set
console.log( first_results.firstName );
console.log( results[0].firstName ); // OR specify which array index to interact directly
</script>

PHP Array Length always 5

I am querying MS SQL Server and storing the results in a json array, then passing the results to Javascript. My issue is that based off if a variable isset the array length SHOULD be either 4 or 5 length. However, the array is ALWAYS showing a length of 5.
This is the php that I am using.
<?php
$sql = "Select ";
if (isset($_GET['namepull'])) {
$sql .= "name,";
}
$sql .= " address, city, state, zip from employeefile";
$db->setQuery($sql);
$rows = $db->loadRowList();
$output = array();
foreach ($rows as $row) {
array_push($output, $row);
}
echo $sql;
$jsondata = json_encode($output[0]);
?>
Which to me the below query strings should show an array length of
4 = Select address, city, state, zip from employeefile
5 = Select name, address, city, state, zip from employeefile
Now the issue that I have is when it hits the below <script> a length of 5 is always produced, regardless of the query. How should I modify the <script> so that an accurate count is returned?
<script>
var arrayfromphp = <?php echo $jsondata; ?>;
alert (arrayfromphp.length);
</script>
If I perform a console.log(arrayfromphp) the last element when the count should be 4 is always undefined x 1
Edit
If I use var_dump below is the output I get (which is what I expect)
Array ( [0] => XXXXXXXXX [1] => New York [2] => New York [3] => 33333 )
Array ( [0] => Jackie [1] => XXXXXXXXX [2] => New York [3] => New York [4] => 33333 )
Edit Again
It appears the issue is stemming from how I am populating a Javascript array from the php array. See edit below with notes above lines
var arrayfromphp = <?php echo $jsondata; ?>;
//Shows accurate count of 4
console.log(arrayfromphp);
var values = [];
if (arrayfromphp.length = 5) {
for (var i = 1; i < arrayfromphp.length; i++) {
values.push(arrayfromphp[i]);
}
} else if (arrayfromphp.length = 4) {
for (var i = 0; i < arrayfromphp.length; i++) {
values.push(arrayfromphp[i]);
}
}
//Shows 5
alert(arrayfromphp.length);
//Shows 5 with undefined x 1
console.log(arrayfromphp);

PHP to decode JSON array and insert into MYSQL database

I am trying to create a PHP script that decodes a JSON array and insert it into a database. So far i've managed to get the script to insert the first row in the array and nothing else.
What would I need to add to this to get the script to insert all the rows in the array?
Here's the array, ignore "listings", I don't need that data yet (It's quite big):
json
Here's the script:
<?php
$servername = "localhost";
$username = "root";
$password = "";
// Create connection
$con = mysql_connect($servername, $username, $password);
//select db
$selected = mysql_select_db("ed",$con);
$json_obj = file_get_contents("stations.json");
//convert to stdclass object
$arr = json_decode($json_obj,true);
//store the element values into variables
$id = $arr[0]["id"];
$name = $arr[0]["name"];
$system_id = $arr[0]["system_id"];
$max_landing_pad_size = $arr[0]["max_landing_pad_size"];
$distance_to_star = $arr[0]["distance_to_star"];
$faction = $arr[0]["faction"];
$government = $arr[0]["government"];
$allegiance = $arr[0]["allegiance"];
$state = $arr[0]["state"];
$type = $arr[0]["type"];
$has_blackmarket = $arr[0]["has_blackmarket"];
$has_commodities = $arr[0]["has_commodities"];
$has_refuel = $arr[0]["has_refuel"];
$has_repair = $arr[0]["has_repair"];
$has_rearm = $arr[0]["has_rearm"];
$has_outfitting = $arr[0]["has_outfitting"];
$has_shipyard = $arr[0]["has_shipyard"];
//insert values into mysql database
$sql="INSERT INTO stations (station_id, name, system_id, max_landing_pad_size, distance_to_star, faction, government, allegiance, state, type, has_blackmarket, has_commodities, has_refuel, has_repair, has_rearm, has_outfitting, has_shipyard)
VALUES ('$id', '$name', '$system_id', '$max_landing_pad_size', '$distance_to_star', '$faction', '$government', '$allegiance', '$state', '$type', '$has_blackmarket', '$has_commodities', '$has_refuel', '$has_repair', '$has_rearm', '$has_outfitting', '$has_shipyard')";
if(!mysql_query($sql,$con)) //$con is mysql connection object
{
die('Error : ' . mysql_error());
}
?>
try this.
$arr = json_decode($json_obj,true);
$sql = 'INSERT INTO stations (`';
$sql.= implode('`,`', array_keys( $arr[0] ) );
$sql.= '`) values (\'';
$sql.= implode('\',\'', $arr[0] );
$sql.= '\')';
Use foreach
$arr = json_decode($json_obj,true);//decode object
foreach($arr as $ar){
$id = $ar["id"];
$name = $ar["name"];
$system_id = $ar["system_id"];
$max_landing_pad_size = $ar["max_landing_pad_size"];
$distance_to_star = $ar["distance_to_star"];
$faction = $ar["faction"];
$government = $ar["government"];
$allegiance = $ar["allegiance"];
$state = $ar["state"];
$type = $ar["type"];
$has_blackmarket = $ar["has_blackmarket"];
$has_commodities = $ar["has_commodities"];
$has_refuel = $ar["has_refuel"];
$has_repair = $ar["has_repair"];
$has_rearm = $ar["has_rearm"];
$has_outfitting = $ar["has_outfitting"];
$has_shipyard = $ar["has_shipyard"];
//insert values into mysql database
$sql="INSERT INTO stations (station_id, name, system_id, max_landing_pad_size, distance_to_star, faction, government, allegiance, state, type, has_blackmarket, has_commodities, has_refuel, has_repair, has_rearm, has_outfitting, has_shipyard)
VALUES ('$id', '$name', '$system_id', '$max_landing_pad_size', '$distance_to_star', '$faction', '$government', '$allegiance', '$state', '$type', '$has_blackmarket', '$has_commodities', '$has_refuel', '$has_repair', '$has_rearm', '$has_outfitting', '$has_shipyard')";
if(!mysql_query($sql,$con)) //$con is mysql connection object
{
die('Error : ' . mysql_error());
}
}
For big amounts of data like in this case, you would want to execute the query just once, or you'll burden your database unnecessarily. For this, you can build your query with all the data being inserted and then execute it, like so:
<?php
$arr = json_decode($json_obj,true);//decode object
$query = "INSERT into stations (station_id, name, system_id, max_landing_pad_size, distance_to_star, faction, government, allegiance, state, type, has_blackmarket, has_commodities, has_refuel, has_repair, has_rearm, has_outfitting, has_shipyard) values ";
foreach($arr as $ar) {
$query .= "($ar['id'],$ar['name'],$ar['system_id'],
$ar['max_landing_pad_size'],$ar['distance_to_star'],$ar['faction'],
$ar['government'],$ar['allegiance'],$ar['state'],
$ar['type'],$ar['has_blackmarket'],$ar['has_commodities'],
$ar['has_refuel'],$ar['has_repair'],$ar['has_rearm'],
$ar['has_outfitting'],$ar['has_shipyard']),";
}
$query = rtrim(",",$query);
if(!mysql_query($query,$con)) //$con is mysql connection object
{
die('Error : ' . mysql_error());
}
In case you want to know, your original code doesn't work because you're just grabbing the first row from the json ($arr[0]). You need to loop through the data to get all the rows.

Categories

Resources