PHP SQLITE3 randomly not inserting data into database - php

I'm parsing a json file to add data to a sqlite database. It works fine apart from the fact that some entries I retrieve from the json file are just not added completely. As an example see this array I got from the json file:
(
[0] => Array
(
[Id] => 4215717
[Guid] => a2fd45b0-c602-4c82-bb30-19aba8bfacdf
[IsRawData] =>
[Name] => test 1
[State] => Released
[Created] => 2015-10-25T10:21:13Z
[CreatorId] => 65edfb59-8087-4f20-81d8-1dc7b94c5624
[Modified] => 2020-02-19T13:08:07Z
[ModifierId] => 65edfb59-8087-4f20-81d8-1dc7b94c5624
[EntryId] => 377794
[LanguageId] => Array
(
[PrimaryLangId] => 7
[SubLangId] => 1
)
)
[1] => Array
(
[Id] => 4215718
[Guid] => 4609ace8-8e6f-457d-a0ae-faa29950cdcb
[IsRawData] =>
[Name] => test 2
[State] => Released
[Created] => 2015-10-25T10:21:41Z
[CreatorId] => 65edfb59-8087-4f20-81d8-1dc7b94c5624
[Modified] => 2017-01-18T13:30:05Z
[ModifierId] => 65edfb59-8087-4f20-81d8-1dc7b94c5624
[EntryId] => 377794
[LanguageId] => Array
(
[PrimaryLangId] => 9
[SubLangId] => 1
)
)
)
For some entries I add to the db using the code below, I randomly only have the first entry from the array written to the db and I can't figure out a pattern for which entries it worked and for which ones it didn't.
Is there something wrong with my code? Or do you see any issues that could cause this behaviour?
// Prepare statement to propagate terms table
$termStmt = $o_db->prepare("INSERT INTO terms
(entryID, termID, term, status, wordclass, usage, type,
primaryLangID, secondaryLangID )
VALUES (:entryID, :termID, :term, :status, :wordclass, :usages, :types,
:primaryLangID, :secondaryLangID)");
// Bind term parameters
$termStmt->bindParam(':entryID', $i_entryID);
$termStmt->bindParam(':termID', $i_termID);
$termStmt->bindParam(':term', $s_term);
$termStmt->bindParam(':status', $s_status);
$termStmt->bindParam(':wordclass', $s_wordclass);
$termStmt->bindParam(':usages', $s_usage);
$termStmt->bindParam(':types', $s_type);
$termStmt->bindParam(':project', $s_project);
$termStmt->bindParam(':primaryLangID', $i_primaryLangID);
$termStmt->bindParam(':secondaryLangID', $i_secondaryLangID);
foreach ($a_entryData as $entry){
$entryID = $entry['entryID']; // entryID comes from another table in the db to get the full entry
$fullEntry = getEntry($entryID); //get entry from json
foreach ($fullEntry as $term){
foreach($term as $termEntry) {
$i_entryID = $termEntry['EntryId'];
$i_termID = $termEntry['Id'];
$s_term =$termEntry['Name'];
$s_status =$termEntry['State'];
$i_primaryLangID = $termEntry['LanguageId']['PrimaryLangId'];
$i_secondaryLangID = $termEntry['LanguageId']['SubLangId'];
// Now get the term properties and the corresponding values
$a_properties = getTermProperties($i_termID);
$a_propertyValues = propertyValues($a_properties);
$a_properties = getTermProperties($i_termID);
$a_values = propertyValues($a_properties);
if (isset($a_values['Wortklasse'])){
$s_wordclass = $a_values['Wortklasse'];
}else{
$s_wordclass = "N\A";
}
if (isset($a_values['Verwendung'])){
$s_usage = $a_values['Verwendung'];
}else{
$s_usage = "N\A";
}
if (isset($a_values['Benennungstyp'])){
$s_type = $a_values['Benennungstyp'];
}else{
$s_type = "N\A";
}
// Execute term statement and add data to the table
$termStmt->execute();
}
}
}
Thanks for your help :)

Related

Alphabetizing multidimensional array with SQL or PHP

I'm working on programming a gradebook, and I've ran into a bit of an issue I'm trying to figure out how to approach.
I have three tables which are at play in this script: (1) the "assignments" table which contains info about each assignment, (2) the "assignGrades" table which contains student scores on assignments (3) the "students" table which contains student information.
Now, the problem is coming whenever I add a new student to the class. Logically, if a student joins a class mid-semester, they would not be assigned "past work" from earlier in the year. With this in mind, there would be no "connection" for an INNER JOIN statement. I have already tried using "LEFT JOIN" and "RIGHT JOIN" in this instance, but I am not having any luck.
Whenever I go to build a PHP array with the SQL statement below, I am running into a problem. If a student was added mid year, they are not properly alphabetizing into the array, which comes from the SELECT statement and the way this is organized. See the example below for student "Amy Appleton" which was added mid year, and is not in proper alphabetical order.
HOW I NEED HELP / DESIRED END RESULT:
I am trying to determine how to alphabetize my $array to be organized in order of last name. I have determined I will either accomplish this through rewriting my SQL statement or through using some sort of PHP usort, although I would much rather organize data on the SQL side if possible. My best guess would be to accomplish this through a LEFT JOIN, but I have tried every variation possible within my SQL statement and have not gotten any desired results.
SQL statement used:
SELECT students.firstName, students.lastName, assignments.assID, assignments.assEmoji, assignments.points, assignments.title, assignments.assigned, assignments.due, assignGrades.*
FROM students
LEFT JOIN assignGrades ON students.usid = assignGrades.usid
LEFT JOIN assignments ON assignGrades.assID = assignments.assID
WHERE subID=? OR subID IS NULL ORDER BY due, lastName, firstName
Snipet from PHP that is building the $array
while ($row = mysqli_fetch_assoc($results)) {
$array['assignments'][$row['assID']]['assEmoji'] = $row['assEmoji'];
$array['assignments'][$row['assID']]['title'] = $row['title'];
$array['assignments'][$row['assID']]['points'] = $row['points'];
$array['assignments'][$row['assID']]['assigned'] = $row['assigned'];
$array['assignments'][$row['assID']]['due'] = $row['due'];
$array['students'][$row['usid']]['firstName'] = $row['firstName'];
$array['students'][$row['usid']]['lastName'] = $row['lastName'];
$array['students'][$row['usid']]['fullName'] = $row['firstName']." ". $row['lastName'];
if ($row['status'] == 'graded' || $row['status'] == 'missing') {
$array['students'][$row['usid']]['earned'] = $array['students'][$row['usid']]['earned'] + $row['score'];
$array['students'][$row['usid']]['maxpts'] = $array['students'][$row['usid']]['maxpts'] + $row['points'];
}
$array['students'][$row['usid']]['submissions'][$row['assID']]['workID'] = $row['workID'];
$array['students'][$row['usid']]['submissions'][$row['assID']]['status'] = $row['status'];
if (isset($row['submitted'])) {$array['students'][$row['usid']]['submissions'][$row['assID']]['submitted'] = $row['submitted'];}
if (isset($row['method'])) {$array['students'][$row['usid']]['submissions'][$row['assID']]['method'] = $row['method'];}
if (isset($row['score'])) {$array['students'][$row['usid']]['submissions'][$row['assID']]['score'] = $row['score'];}
if (isset($row['score'])) {$array['students'][$row['usid']]['submissions'][$row['assID']]['points'] = $row['points'];}
if (isset($row['graded'])) {$array['students'][$row['usid']]['submissions'][$row['assID']]['graded'] = $row['graded'];}
if (isset($row['method'])) {$array['students'][$row['usid']]['submissions'][$row['assID']]['method'] = $row['method'];}
}
return $array;
Example print_r($array) from the SQL statement (Amy Appleton should appear on the top of $array['students'] since she is alphabetically before the other two students. However, since there is no entry on the assignGrades table for assignment #9 for her, she appears at the bottom)
Array
(
[assignments] => Array
(
[9] => Array
(
[assEmoji] => ✏️
[title] => Beginning of Year Activities
[points] => 10
[assigned] => 2021-08-16
[due] => 2021-08-20 15:00:00
)
[10] => Array
(
[assEmoji] => ✏️
[title] => Mid Year Project
[points] => 10
[assigned] => 2021-09-23
[due] => 2021-09-30 15:00:00
)
)
[students] => Array
(
[11] => Array
(
[firstName] => Zeke
[lastName] => Lee
[fullName] => Zeke Lee
[earned] => 103
[maxpts] => 120
[submissions] => Array
(
[9] => Array
(
[workID] => 539
[status] => graded
[submitted] => 2021-08-17 08:15:48
[method] => wall
[score] => 9
[points] => 10
[graded] => 2021-09-22 10:26:54
)
[10] => Array
(
[workID] => 541
[status] => graded
[submitted] => 2021-09-23 08:15:48
[method] => wall
[score] => 9
[points] => 10
[graded] => 2021-09-23 10:26:54
)
)
)
[12] => Array
(
[firstName] => John
[lastName] => Smith
[fullName] => John Smith
[earned] => 91
[maxpts] => 110
[submissions] => Array
(
[9] => Array
(
[workID] => 540
[status] => graded
[submitted] => 2021-08-17 08:45:48
[method] => wall
[score] => 7
[points] => 10
[graded] => 2021-09-22 10:28:54
)
[10] => Array
(
[workID] => 590
[status] => graded
[submitted] => 2021-09-23 09:15:48
[method] => wall
[score] => 9
[points] => 10
[graded] => 2021-09-23 11:24:54
)
)
)
[13] => Array
(
[firstName] => Amy
[lastName] => Appleton
[fullName] => Amy Appleton
[earned] => 91
[maxpts] => 110
[submissions] => Array
(
[10] => Array
(
[workID] => 913
[status] => graded
[submitted] => 2021-09-23 10:45:48
[method] => wall
[score] => 7
[points] => 10
[graded] => 2021-09-23 12:31:54
)
)
)
)
)
Array structure:
$array['assignments'][assID][details]
$array['students'][usid][details]
$array['students'][usid]['submissions'][assID][details]
Screenshots of table structure from SQL
Screenshot of CSV dump from SQL query
The main issue I see is that your query is trying to do too much. It is trying to get assignments in a specific order (by due), as well as students and their submissions in a different order (by lastName, firstName). For this reason, I would break this up into 2 separate queries. You can combine the datasets later to make your final data structure.
retrieve the assignments and order them by due date. This is a very simple query and the result set can be used directly.
retrieve all students and their submissions, if they exist, and order them by lastName, first name. Then, in PHP, manipulate the dataset into the format you need.
Pseudocode
// Get assignments. These can be used directly in your data structure `$combined`.
//
// Order by due date
$assignments = SELECT ... FROM assignments
WHERE ...
ORDER BY due;
// Get students and their assignments. These need to be manipulated to fit your
// requirements. Use a left join here because a student may not have started
// an assignment yet.
//
// Order by lastName, firstName
$students = SELECT ... FROM students a
LEFT JOIN assignGrades b ON b.usid = a.usid
ORDER BY lastName, firstName;
// See http://sandbox.onlinephpfunctions.com/code/9460c51954f8ea00f7ba75adadfcbf91fc03076e
// Loop over the student/submission dataset and manipulate it.
$studentMapping = [];
foreach($students as $row) {
// Build up student data if it doesn't already exist.
// Importantly, create an empty submissions element. If the student's
// submission doesn't exist, this is what will be returned.
$student = $studentMapping[$row['usid']] ?? [];
if (empty($student)) {
$student = [
'firstName' => $row['lastName'],
'lastName' => $row['lastName'],
...
'submissions' => [],
];
}
// Build up submissions data for the student if they have submitted an assignment.
// If they haven't submitted an assignment yet, their submissions array will remain empty.
if (!empty($row['assignment_id'])) {
$student['submissions'][] = [
'assignmentId' => $row['assignment_id'],
'status' => $row['status'],
...
];
}
// Finally, assign the student (and their submissions) to the $studentMapping array.
$studentMapping[$row['usid']] = $student;
}
// Now combine them into your final datastructure.
$combined = [
'assignments' => $assignments,
'students' => $studentMapping,
];

Create PHP Array Where Matching Keys have Some Value

This is the first post from a PHP noob. My question relates to an HTML/PHP form which posts the following three types of data generated by a MySQL query:
ID (always posted via a hidden input field)
Mileage (only some entries may be completed, others might be left blank)
Vehicle Type (always posted via a hidden input field)
This data is all for one of three companies that are selected on the page preceding the data-posting page ie.
Step One: Choose company and year. Press submit.
Step Two: See results from MySQL query and enter in mileages where necessary. Press submit.
Step Three: (that's why I'm here)
I've stuffed this data into what I (probably mistakenly) believe is a multidimensional array called $idmilearray by using the following code:
if(isset($_POST['mileage'])) {
$mileagenumber = $_POST['mileage'];
}
if(isset($_POST['idnos'])) {
$idnumber = $_POST['idnos'];
}
if(isset($_POST['vehicle'])) {
$vehicletype = $_POST['vehicle'];
}
$idmilearray = array(
'ids' => $idnumber,
'mileage' => $mileagenumber,
'vtype' => $vehicletype
);
foreach($idmilearray as $inputs) {
$inputs = $idmilearray['ids'];
$inputs = $idmilearray['mileage'];
$inputs = $idmilearray['vtype'];
}
If I execute a print_r on the $idmilearray I get the following results:
Array
(
[ids] => Array
(
[0] => 35
[1] => 22
[2] => 32
[3] => 38
[4] => 36
[5] => 39
[6] => 16
[7] => 20
[8] => 48
[9] => 46
)
[mileage] => Array
(
[0] => 334
[1] => 56
[2] =>
[3] => 43
[4] =>
[5] =>
[6] =>
[7] =>
[8] => 11
[9] => 5
)
[vtype] => Array
(
[0] => 10T
[1] => 10T
[2] => 10T
[3] => Artic
[4] => 10T
[5] => Artic
[6] => Artic
[7] => 10T
[8] => Artic
[9] => 10T
)
What I would like to do is to create another array (the values of which I can use in later SQL queries) but only where the keys contain something in [ids][0], [mileage][0] and [vtype][0] and so on and so forth. I'd like to use [mileage] as the 'reference array'.
I've been playing around with array_intersect_key and array_diff_key but I've hit a big and rather a nasty wall. Can anyone help or give some pointers?
Thanks very much for your time.
Regards,
External.
You can use what you have to insert directly into mysql as follows:
foreach ( $idmilearray['mileage'] as $KEY => $VAL ) {
if ( empty($VAL) ) continue;
$query = "INSERT INTO `tableName` (id, mileage, vtype) VALUES ('{$idmilearray['ids'][$KEY]}', '$VAL', '{$idmilearray['vtype'][$KEY]}')";
}
Or if you really want to merge everything for further processing or whatever reason you can do it like so:
$NewArray = [];
foreach ( $idmilearray['mileage'] as $KEY => $VAL ) {
if ( empty($VAL) ) continue;
$NewArray[] = array('id' => $idmilearray['ids'][$KEY], 'mileage' => $VAL, 'vtype' => $idmilearray['vtype'][$KEY]);
}
Ofcourse there are many other possible ways to do this, but these are the easiest given what you currently have.
Just add another foreach, inside your existing foreach and fill your new array by checking the old array values with if (!empty($old_array)) {}
Example:
foreach($idmilearray as $inputs) {
$inputs = $idmilearray['ids'];
$inputs = $idmilearray['mileage']; // This is the one you want, right?
$inputs = $idmilearray['vtype'];
}
To do the job you need, it would be something like this:
$new_array = []; // Short array syntax (PHP 5.3+)
foreach($idmilearray as $inputs) {
$inputs = $idmilearray['ids'];
foreach($idmilearray['mileage'] as $mileage) {
if (!empty($mileage)) {
$new_array[] = $mileage;
}
}
$inputs = $idmilearray['vtype'];
}
Now you have new array ($new_array) filled only with the keys that links to existing values.
I hope it helps you.

Saving Mikrotik Simple Queue Statistic PHP API

I want to save the statistics of the Mikrotik /simple queue using the PHP API. I have been able to pull the data but seems my implementation on the PHP side is a problem. The following is the code and the resulting array object.
foreach ($util->setMenu('/queue simple')->getAll() as $queueEntry) {
// $lasArray = $queueEntry;
print_r($queueEntry);
}
Excerpt for Result since its returning for all users in the office, I have choosen just to display for one user. Take it that PEAR2\Net\RouterOS\Response Object is retuned for all users, i.e all in this case over 50 users. I would like to save this data to database but only the relevant ones like [.id], [name], [target], [limit-at], [max-limit] and [bytes], any assistance here would be highly regarded.
PEAR2\Net\RouterOS\Response Object
(
[unrecognizedWords:protected] => Array
(
)
[_type:PEAR2\Net\RouterOS\Response:private] => !re
[attributes:protected] => Array
(
[.id] => *12
[name] => GikundaPhone
[target] => 192.168.1.108/32
[parent] => none
[packet-marks] =>
[priority] => 8/8
[queue] => default-small/default-small
[limit-at] => 128000/384000
[max-limit] => 384000/384000
[burst-limit] => 0/0
[burst-threshold] => 0/0
[burst-time] => 0s/0s
[bucket-size] => 0.1/0.1
[bytes] => 16515474/129310087
[total-bytes] => 0
[packets] => 127812/133712
[total-packets] => 0
[dropped] => 76/8667
[total-dropped] => 0
[rate] => 0/0
[total-rate] => 0
[packet-rate] => 0/0
[total-packet-rate] => 0
[queued-packets] => 0/0
[total-queued-packets] => 0
[queued-bytes] => 0/0
[total-queued-bytes] => 0
[invalid] => false
[dynamic] => false
[disabled] => false
)
[_tag:PEAR2\Net\RouterOS\Message:private] =>
)
Have found and answer to my own question. This is what I have done. The
foreach ($util->setMenu('/queue simple')->getAll() as $queueEntry) {
// $lasArray = $queueEntry;
print_r($queueEntry);
}
provided alot of information thats unnecessary, so I have found about the routeros_api.class.php downloadable from here and followed but modified information from here. Then just used
$address = 'IPV4_Address_of_router';
$user = 'username_of_router';
$pass = 'password_of_router';
require('routeros_api.class.php');
$API = new routeros_api();
$API->debug = false;
// router credentials and after including the routeros_api.cass.php
if ($API->connect($address, $user, $pass)) {
$results = $API->comm("/queue/simple/print");
foreach ($results as $row) {
$clientName = $row['name'];
$clientIP = $row['target'];
$clientMaxDown = $row['limit-at'];
$clientMaxUp = $row['max-limit'];
$clientDownloads = $row['bytes'];
}
}
Only thing remaining was to save to database which is simple. Maybe someone may get helped someday by this.

Problems with array when getting data from a database

I'm trying to get some data from my database, and then pass it into an array for later use. I am using MySQLi for my driver.
Here's my code:
// Build a query to get skins from the database
$stmt = $mysqli->prepare('SELECT id, name, description, author, timestamp, url, preview_filename FROM `skins` LIMIT 0, 5');
$stmt->execute();
$stmt->bind_result($result['id'], $result['name'], $result['desc'], $result['auth'], $result['time'], $result['url'], $result['preview']);
// The skins array holds all the skins on the current page, to be passed to index.html
$skins = array();
$i = 0;
while($stmt->fetch())
{
$skins[$i] = $result;
$i++;
}
print_r($skins);
The problem is, when this executes, the $skins array contains the last result row from the query. This is the print_r of $skins:
Array
(
[0] => Array
(
[id] => 3
[name] => sdfbjh
[desc] => isdbf
[auth] => dfdf
[time] => 1299970810
[url] => http://imgur.com/XyYxs.png
[preview] => 011e5.png
)
[1] => Array
(
[id] => 3
[name] => sdfbjh
[desc] => isdbf
[auth] => dfdf
[time] => 1299970810
[url] => http://imgur.com/XyYxs.png
[preview] => 011e5.png
)
[2] => Array
(
[id] => 3
[name] => sdfbjh
[desc] => isdbf
[auth] => dfdf
[time] => 1299970810
[url] => http://imgur.com/XyYxs.png
[preview] => 011e5.png
)
)
As you can see, the last result from the query is populating all of the array entries for some reason.
Can anyone explain this behaviour and tell me what I'm doing wrong? Thanks. :)
EDIT: Here's the solution:
while($stmt->fetch())
{
foreach($result as $key=>$value)
{
$tmp[$key] = $value;
}
$skins[$i] = $tmp;
$i++;
}
Quoting the (now) first note on the mysqli::fetch manual page, emphasis mine :
the problem is that the $row returned is reference and not data.
So, when you write $array[] = $row, the $array will be filled up with the last element of the dataset.

Cakephp: question about saveall() with multiselect

I'm wondering what the cleanest way is to implement a cakephp form where 1 control is a multi-select and the rest are text fields or single-selects, and then the data is inserted as multiple rows with a saveall(). So for example a form is selected with these values:
textfield A
value=Foo
mulit-select B
values=US,Mexico,Canada
single=select C
value=10
and so I want to insert these rows into the database with a saveall():
Foo,US,10
Foo,Mexico,10
Foo,Canada,10
Now I know in the add view I can use this format for the input statement:
input('Model.0.field1',...)
but I'm wondering if I can mix that in that same form with inputs formatted like
input('Model.field2',....).
Update:
When I mix and match the single-select and multiple-select controls, the form data gets submitted like this:
Array
(
[Alert] => Array
(
[schedule_id] => 75
[user_id] => 6
[0] => Array
(
[frequency] => Array
(
[0] => WEEKLY
[1] => MONTHLY
)
)
[limit_value] => .03
[limit_adjustment] => 0
[type] => LIMIT
[disabled] => 0
)
)
I tried passing that data into saveall() but it treats it like a single record.
Update2: I think saveAll() requires that the multiple rows of data be formatted like this:
Array
(
[Article] => Array(
[0] => Array
(
[title] => title 1
)
[1] => Array
(
[title] => title 2
)
)
)
So it looks like after the submit I'm going to need some javascript code that will restructure the array.
I have something that works... I'm not sure if it takes full advantage of all of cake's "automagic" capabilities, but I don't think it's too convoluted.
So I just added the following code to my controller's add function:
if (!empty($this->data)) {
//debug($this->data, true);
/* begin custom code */
$multiselect = $this->data['Alert']['entity_id'];
$tmp2 = array();
foreach ($multiselect as $item)
{
$tmp = $this->data['Alert'];
$tmp['entity_id'] = $item;
array_push($tmp2,$tmp);
}
$this->data['Alert'] = $tmp2;
debug($this->data,true);
/* end custom code */
$this->Alert->create();
//restructure data
if ($this->Alert->saveAll($this->data['Alert'])) {
$this->Session->setFlash(__('The alert has been saved', true));
//$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The alert could not be saved. Please, try again.', true));
}
and that converts my data to this:
Array
(
[Alert] => Array
(
[0] => Array
(
[schedule_id] => 74
[entity_id] => 1
[user_id] => 6
[frequency] => HOURLY
[limit_value] => .02
[limit_adjustment] => 0
[type] => LIMIT
[disabled] => 1
)
[1] => Array
(
[schedule_id] => 74
[entity_id] => 2
[user_id] => 6
[frequency] => HOURLY
[limit_value] => .02
[limit_adjustment] => 0
[type] => LIMIT
[disabled] => 1
)
)
)

Categories