Why XMLReader repeat mysql insert function inside while and can't stop? - php

I am using XMLReader to import huge xml file by elements to MySQL database. Xml contains 1 547 772 tags (element) named 'RECORD'.
XML example
<?xml version="1.0" encoding="utf-8"?>
<RECORD><NAME>ДОШКІЛЬНИЙ НАВЧАЛЬНИЙ ЗАКЛАД №1 ЗАГАЛЬНОГО РОЗВИТКУ УЖГОРОДСЬКОЇ МІСЬКОЇ РАДИ ЗАКАРПАТСЬКОЇ ОБЛАСТІ</NAME><SHORT_NAME>ДНЗ №1</SHORT_NAME><EDRPOU>34888585</EDRPOU><ADDRESS>88000, Закарпатська обл., місто Ужгород, ВУЛИЦЯ М.ВОВЧКА, будинок 47, "А"</ADDRESS><BOSS>НАКОНЕЧНА ОЛЕНА АНАТОЛІЇВНА</BOSS><KVED>85.10 Дошкільна освіта</KVED><STAN>зареєстровано</STAN><FOUNDERS><FOUNDER>УПРАВЛІННЯ ОСВІТИ УЖГОРОДСЬКОЇ МІСЬКОЇ РАДИ, розмір внеску до статутного фонду - 0.00 грн.</FOUNDER>...</FOUNDERS></RECORD>...
For MySQL connection use
function connectBase(){
include __DIR__ . '/../../settings/sql.set.php';
$mysql = mysqli_connect($_sqlhost, $_sqluser, $_sqlpass, $_sqldb);
mysqli_query($mysql, "Set charset utf8");
mysqli_query($mysql, "Set character_set_client = utf8");
mysqli_query($mysql, "Set character_set_connection = utf8");
mysqli_query($mysql, "Set character_set_results = utf8");
mysqli_query($mysql, "Set collation_connection = utf8_general_ci");
return $mysql;
}
Main function for parsing
function XMLReaderToDB($setting = false)
{
$mysql = connectBase();
$dir = __DIR__ . '/../../tmp/';
$xmlURL = $dir . $setting['file'];
$xml = new XMLReader();
$xml->open($xmlURL);
$start_time = time();
$start = $setting['start'];
$limit = $setting['limit'];
$stop = $start + $limit;
$i = 0;
$count = 0;
$result = 1;
while($xml->read())
{
if ($xml->nodeType == XMLReader::ELEMENT && $xml->name == $setting['tag']) {
$item[] = "('items', '" . mysqli_real_escape_string($mysql, $xml->readOuterXML()) . "')";
}
if ($xml->nodeType == XMLReader::END_ELEMENT && $xml->name == $setting['tag']) {
$i++;
$count++;
if ($count >= 500) {
insertXMLtoDB($mysql, $item);
$item = array();
$count = 0;
}
}
if($i == $stop){
break;
}
}
$xml->close();
insertXMLtoDB($mysql, $item);
$mysql->close();
$end_time = time();
$time_elapsed_secs = $end_time - $start_time;
echo '<br/>Items: ' . $i . '<br/>';
echo 'Start: ' . date('H:i:s', $start_time) . '<br/>';
echo 'End: ' . date('H:i:s', $end_time) . '<br/>';
echo $time_elapsed_secs . ' sec. (' . ($time_elapsed_secs /60) . ' min.)';
die;
}
And for MySQL insert
function insertXMLtoDB($mysql, $data = false){
mysqli_query($mysql,"INSERT INTO _parse_tmp (parse_key, parse_value) VALUES " . implode(", ", $data));
$data = array();
// echo 'Success';
}
But, MySQL requests don't stop after 1 547 772 inserts and "while" continues to run. I notice if uncommenting echo 'Success'; in insertXMLtoDB function, "while" is stopping at 1 547 772 inserts and finishing correctly.
What is wrong in my functions?

I've never personally used XMLReader however, I'd assume you could try to add another condition to your statement such as while($xml->read() && $i != $stop) opposed to having it within your loop directly. Ah also just noticed after your usage of the function insertXMLtoDB you re-declare $data although you'll notice you set it to NULL every time your call the function, therefore setting it to an array is pointless.

I can't understand why the script doesn't work fine. That's why I decided to change it.
function XMLReaderToDB($setting = false)
{
$mysql = connectBase();
$dir = __DIR__ . '/../../tmp/';
$xmlURL = $dir . $setting['file'];
$xml = new XMLReader();
$xml->open($xmlURL);
$start_time = time();
$start = $setting['start'];
$limit = $setting['limit'];
$stop = $start + $limit;
$i = 0;
$count = 0;
while (($valid = $xml->read()) && $xml->name !== $setting['tag']) ;
while ($valid) {
$i++;
$count++;
$item[] = "('" . $setting['type'] . "', '" . mysqli_real_escape_string($mysql, $xml->readOuterXML()) . "')";
if ($count == 500) {
insertXMLtoDB($mysql, $item);
$item = array();
$count = 0;
}
$valid = $xml->next($setting['tag']);
}
$xml->close();
insertXMLtoDB($mysql, $item);
$mysql->close();
$end_time = time();
$time_elapsed_secs = $end_time - $start_time;
echo '<br/>Items: ' . $i . '<br/>';
echo 'Start: ' . date('H:i:s', $start_time) . '<br/>';
echo 'End: ' . date('H:i:s', $end_time) . '<br/>';
echo $time_elapsed_secs . ' sec. (' . ($time_elapsed_secs /60) . ' min.)';
return;
}

Related

How give colour to a cell in pdf using php?

I need to give color to a specific cell in pdf which is generated from my MySQL database, How to set the color to the specific value?
I have no clue about giving color to the specific value, I there any way help me out?
my pdf generate page is:
$fdate = date('Y-m-d H:i:s', strtotime($fromdate));
$tdate = date('Y-m-d H:i:s', strtotime( $todate));
/*$channelsCol = Channels::find()
->select(['channel_name'])
->where('DeviceRefID != :id',['id' => 0 ])
->orderBy('channel_no')
->all();*/
$channelscol = \Yii::$app->db
->createCommand("select channel_name from channels where deviceRefID !=0")
->queryAll();
$pdfpages = $this->getNoOfPdfs(count($channelscol));
$noOfPages = count($pdfpages[0]);
$collist=[];
$selectlist=[];
for($i=0; $i < $noOfPages;$i++)
{
$collist[$i] = 'Select SQL_BUFFER_RESULT "LogDateTime ",';
$selectlist[$i] = 'select LogDateTime,';
}
$count =0;
$counter=1;
for($i=0;$i<$noOfPages;$i++)
{
for($j=$pdfpages[0][$i];$j<$pdfpages[1][$i];$j++)
{
$collist[$i] = $collist[$i] . '"'.$channelscol[$j-1]['channel_name'] .'",';
$selectlist[$i] = $selectlist[$i] . 'Channel'.$j.'Value,';
$count = $count + 1;
}
}
for($i=0;$i <$noOfPages ;$i++)
{
$collist[$i] = rtrim($collist[$i],",");
$selectlist[$i] = rtrim($selectlist[$i],",");
}
//$path ="/var/www/devicesadmin/yii-app/web/devicelog/devicelog" . date("Y-m-d-H-i-s").".csv";
$logfilename =[];
$logfailure="";
for($i=0;$i < $noOfPages; $i++)
{
$logfilename[$i] = $pdfpages[2][$i] . date("Y-m-d-H-i-s") . mt_rand() . ".csv";
//$path ='D:/Raffi/ProjectsPhp/DevicesAdminProject/yii-app/web/devicelog//' . $logfilename[$i];
$path = "/var/www/devicesadmin/yii-app/web/devicelog/" . $logfilename[$i];
$export =' INTO OUTFILE "' . $path . '" FIELDS TERMINATED BY "," ENCLOSED BY \'"\' LINES TERMINATED BY \'\\n\' FOR UPDATE';
$whereclause = "where LogDatetime between '" . $fdate . "' and '" .$tdate ."'";
$finalsql = $collist[$i] . ' Union all ' .$selectlist[$i] .' From devicelog '. $whereclause . $export;
try {
Yii::$app->db->createCommand($finalsql)->execute();
//file_put_contents("D:\my.txt", $this->getHTML($path, $header));
//echo html($this->getHTML($path, $header));
//exit();
$pdf=new \PDF('P','mm','Legal');
$pdf->AliasNbPages();
//$pdf=new \PDF('L','mm','Legal',130);
$pdf->AddPage();
$pdf->SetFont('helvetica','',10);
$pdf->WriteHTML($this->getHTML($path));
$logfilename[$i] = "dl" . $pdfpages[2][$i] . date("Y-m-d-H-i-s").".pdf";
//$filename = "D:/Raffi/ProjectsPhp/DevicesAdminProject\yii-app\web\devicelog" . $logfilename[$i];
$filename = "/var/www/devicesadmin/yii-app/web/devicelog/" . $logfilename[$i];
$pdf->Output('F',$filename);
unset($pdf);
} catch(Exception $e) {
}
}
If a pdf is generated, I need to give red color to the values which are above 50. But I can't get the values and give color.

Why can't get the value of weekend in php

I don't know what are the errors of this code because it's suddenly not accurate the showing value to the user like this:
$holidays = array();
$query_holiday = "SELECT * FROM holiday_tbl";
$result = mysqli_query($dbcon, $query_holiday);
while($row_holiday = mysqli_fetch_assoc($result))
{
array_push($row_holiday, $holidays);
}
if(strtotime(date("Y-m-d")) > strtotime($row['due_date']))
{
$currentDate = date("Y-m-d");
$days = (strtotime($currentDate) - strtotime($row['due_date'])) / 86400;
$daysTemp = $days;
for($i=1;$i<$days;$i++)
{
$currentDay = date("D", strtotime("+ ".$i." days"));
$date_loop = date("Y-m-d", strtotime("+ ".$i." days"));
if($currentDay == "Sun" || $currentDay == "Sat")
{
$daysTemp--;
}
else if(in_array($date_loop, $holidays))
{
$daysTemp--;
}
}
echo $daysTemp;
}
The current implementation is rather convoluted. In these cases I find it's always better to start over and try to simplify the logic as much as possible. Here is my take on your problem:
function calculate_days_late($due_date = '', $holidays = array(), $current_date = 'today') {
$days_late = 0;
// Get the timestamps for due date and current date
$current_date_ts = strtotime($current_date);
$due_date_ts = strtotime($due_date);
// If current date is not after due date then not late
if ($current_date_ts <= $due_date_ts) {
return $days_late;
}
$loop_date_ts = $current_date_ts;
while ($loop_date_ts > $due_date_ts) {
// If the looping date is not a weekend or holiday then count it
if ( ! in_array(date('D', $loop_date_ts), array('Sat','Sun'))
&& ! in_array(date('Y-m-d', $loop_date_ts), $holidays)) {
$days_late++;
}
$loop_date_ts = strtotime('-1 day', $loop_date_ts);
}
return $days_late;
}
// Test
echo '2017-09-05 = ' . calculate_days_late('2017-09-05', array(), '2017-09-05') . "\n";
echo '2017-09-06 = ' . calculate_days_late('2017-09-05', array(), '2017-09-06') . "\n";
echo '2017-09-07 = ' . calculate_days_late('2017-09-05', array(), '2017-09-07') . "\n";
echo '2017-09-08 = ' . calculate_days_late('2017-09-05', array(), '2017-09-08') . "\n";
echo '2017-09-09 = ' . calculate_days_late('2017-09-05', array(), '2017-09-09') . "\n";
echo '2017-09-10 = ' . calculate_days_late('2017-09-05', array(), '2017-09-10') . "\n";
echo '2017-09-11 = ' . calculate_days_late('2017-09-05', array(), '2017-09-11') . "\n";
echo '2017-09-12 = ' . calculate_days_late('2017-09-05', array(), '2017-09-12') . "\n";
echo '2017-09-13 = ' . calculate_days_late('2017-09-05', array(), '2017-09-13') . "\n";
Working example: https://eval.in/856018

Returning JSON from a PHP function

I want to transform this PHP function.. that should return JSON data.
<?php
$query = 'SELECT * FROM `' . mix_player::table() . '` a';
if (isset($_GET['cat']) || isset($_GET['order']))
if (isset($_GET['cat'])) {
$query .= ' INNER JOIN `' . mix_player::table_cat_rel() . '` b '
. "ON (a.`id` = b.`idtrack`) WHERE `idcat` = '" . $wpdb->escape($_GET['cat']) . "'";
$random = $wpdb->get_var('SELECT `random`, `order` FROM `' . mix_player::table_categories() . "` WHERE `id` = '"
. $wpdb->escape($_GET['cat']) . "'");
if (!$random)
$order = $wpdb->get_var(NULL, 1);
}
if (isset($_GET['order']))
$order = $_GET['order'];
if ($order != '') {
if (isset($_GET['cat']))
$query .= ' AND ';
else
$query .= ' WHERE ';
$tracks = mix_player::order_list($query, $order);
}
} else {
$random = '0';
}
$query .= ' ORDER BY `id` ASC';
if (isset($tracks) || ($tracks = $wpdb->get_results($query, ARRAY_A))) {
// option "shuffle = true" not always working into mix. Do it our own way...
if ($random == 1) { // shuffle tracks?
list($usec, $sec) = explode(' ', microtime());
mt_srand((float) $sec + ((float) $usec * 100000));
$nrows = count($tracks);
for ($i = 0; $i < $nrows; $i++) {
$j = mt_rand(0, $nrows - 1); // pick j at random
$row = $tracks[$i]; // swap i, j
$tracks[$i] = $tracks[$j];
$tracks[$j] = $row;
}
}
foreach ($tracks as $row) {
$artist = (mix_player::entities($row['artist']));
echo ($artist);
$title = (mix_player::entities($row['title']));
echo ($title);
$url =(xspf_player::entities($row['url']));
echo ($url);
}
}
?>
to display like this json file :
{"title":"title", "artist":"artist","media":"url media.mp3","color":"#56B0E8" },
Can you help me?
Thanks in advance.
You can simply create an array and populate it with your desired values, then return it as JSON:
function tracks2json( $tracks )
{
$retval = array();
foreach( $tracks as $row )
{
$array = array();
$array['artist'] = mix_player::entities($row['artist']);
$array['title'] = mix_player::entities($row['title']);
$array['media'] = 'url '.xspf_player::entities($row['url']);
$array['color'] = '#56B0E8';
$retval[] = $array;
}
return json_encode( $retval );
}
if( isset($tracks) || ($tracks = $wpdb->get_results($query, ARRAY_A)) )
{
// Your MySQL routine here
$json = tracks2json( $tracks );
}
echo json_encode(array("title"=>$title,"artist"=>$artist,"url"=>$url));

update a JSON file using PHP/MYSQL - limit size issue

The code below works great until i have around 25000-30000 objects in the Json array stored. Then the file isn't update anymore.
Does someone know what could be the issue?
foreach ($serials as $key => $serial_list) {
foreach ($serial_list as $key => $serial) {
$url = 'json/voltage/voltage_' . $serial . '.json';
$file = file_get_contents($url, true);
if ($file != true) {
$sql = "SELECT * FROM realtimedata_V WHERE device_serial ='{$serial}' ORDER by timeStamp ASC limit 1200 ";
$result = $db->mysqli->query($sql);
while ($row = $result->fetch_assoc()) {
$voltage_tmp[$serial][] = array(
(int) strtotime($row['timeStamp']) * 1000,
(int) $row['Va'],
(int) $row['Vb'],
(int) $row['Vc']
);
}
echo '<hr>';
echo 'new_datas_' . $serial . '= ' . json_encode($voltage_tmp[$serial]);
echo '<hr>';
file_put_contents($url, json_encode($voltage_tmp[$serial]));
} else {
$data = json_decode($file, true);
if ($data === NULL)
die('Unable to decode');
unset($file);
$AllKeys = array_keys($data);
echo '<hr> Last_Key= <hr>';
echo $last_index = end($AllKeys);
echo '<hr>';
$key = $data[$AllKeys[$last_index]];
$key_unix = $key[0]/1000;
$limit_sql = $last_index +2000;
echo '<hr>';
echo 'Last_date ' . $serial . '= ' . $last_date = date('Y-m-d H:i:s', $key_unix);
echo '<hr>';
echo $sql = "SELECT * FROM realtimedata_V WHERE device_serial ='{$serial}' AND timeStamp > '{$last_date}' ORDER by timeStamp ASC limit {$limit_sql} ";
$result = $db->mysqli->query($sql);
$row_cnt = $result->num_rows;
if ($row_cnt === 0) {
echo 'rows = ' . $row_cnt;
echo '<hr>Any new datas for the serial N°: ' . $serial . '<hr>';
continue;
} else {
while ($row = $result->fetch_assoc()) {
$voltage[$serial][] = array(
(int) strtotime($row['timeStamp']) * 1000,
(int) $row['Va'],
(int) $row['Vb'],
(int) $row['Vc']
);
}
$result = $data + $voltage[$serial];
echo '<hr>';
echo 'new_datas_' . $serial . '= ' . $new_data = json_encode($result);
echo '<hr>';
if (file_put_contents($url, $new_data) === false) {
die('unable to write file');
}
unset($result);
file_put_contents($url, $new_data, LOCK_EX);
//$result->free();
}
}
}
}
I changed the configuration of the php.ini in case of memory limits. But nothing...
I tried in an another server but same issue.
Does someone have an idea?
Thanks

How To Change Numbers Based On Results

I have a follow up question on something I got help with here the other day (No Table Three Column Category Layout).
The script is as follows:
$res = mysql_query($query);
$system->check_mysql($res, $query, __LINE__, __FILE__);
$parent_node = mysql_fetch_assoc($res);
$id = (isset($parent_node['cat_id'])) ? $parent_node['cat_id'] : $id;
$catalist = '';
if ($parent_node['left_id'] != 1)
{
$children = $catscontrol->get_children_list($parent_node['left_id'], $parent_node['right_id']);
$childarray = array($id);
foreach ($children as $k => $v)
{
$childarray[] = $v['cat_id'];
}
$catalist = '(';
$catalist .= implode(',', $childarray);
$catalist .= ')';
$all_items = false;
}
$NOW = time();
/*
specified category number
look into table - and if we don't have such category - redirect to full list
*/
$query = "SELECT * FROM " . $DBPrefix . "categories WHERE cat_id = " . $id;
$result = mysql_query($query);
$system->check_mysql($result, $query, __LINE__, __FILE__);
$category = mysql_fetch_assoc($result);
if (mysql_num_rows($result) == 0)
{
// redirect to global categories list
header ('location: browse.php?id=0');
exit;
}
else
{
// Retrieve the translated category name
$par_id = $category['parent_id'];
$TPL_categories_string = '';
$crumbs = $catscontrol->get_bread_crumbs($category['left_id'], $category['right_id']);
for ($i = 0; $i < count($crumbs); $i++)
{
if ($crumbs[$i]['cat_id'] > 0)
{
if ($i > 0)
{
$TPL_categories_string .= ' > ';
}
$TPL_categories_string .= '' . $category_names[$crumbs[$i]['cat_id']] . '';
}
}
// get list of subcategories of this category
$subcat_count = 0;
$query = "SELECT * FROM " . $DBPrefix . "categories WHERE parent_id = " . $id . " ORDER BY cat_name";
$result = mysql_query($query);
$system->check_mysql($result, $query, __LINE__, __FILE__);
$need_to_continue = 1;
$cycle = 1;
$column = 1;
$TPL_main_value = '';
while ($row = mysql_fetch_array($result))
{
++$subcat_count;
if ($cycle == 1)
{
$TPL_main_value .= '<div class="col'.$column.'"><ul>' . "\n";
}
$sub_counter = $row['sub_counter'];
$cat_counter = $row['counter'];
if ($sub_counter != 0)
{
$count_string = ' (' . $sub_counter . ')';
}
else
{
if ($cat_counter != 0)
{
$count_string = ' (' . $cat_counter . ')';
}
else
{
$count_string = '';
}
}
if ($row['cat_colour'] != '')
{
$BG = 'bgcolor=' . $row['cat_colour'];
}
else
{
$BG = '';
}
// Retrieve the translated category name
$row['cat_name'] = $category_names[$row['cat_id']];
$catimage = (!empty($row['cat_image'])) ? '<img src="' . $row['cat_image'] . '" border=0>' : '';
$TPL_main_value .= "\t" . '<li>' . $catimage . '' . $row['cat_name'] . $count_string . '</li>' . "\n";
++$cycle;
if ($cycle == 7) // <---- here
{
$cycle = 1;
$TPL_main_value .= '</ul></div>' . "\n";
++$column;
}
}
if ($cycle >= 2 && $cycle <= 6) // <---- here minus 1
{
while ($cycle < 7) // <---- and here
{
$TPL_main_value .= ' <p> </p>' . "\n";
++$cycle;
}
$TPL_main_value .= '</ul></div>'.$number.'
' . "\n";
}
I was needing to divide the resulting links into three columns to fit my html layout.
We accomplished this by changing the numbers in the code marked with "// <---- here".
Because the amount of links returned could be different each time, I am trying to figure out how to change those numbers on the fly. I tried using
$number_a = mysql_num_rows($result);
$number_b = $number_a / 3;
$number_b = ceil($number_b);
$number_c = $number_b - 1;
and then replacing the numbers with $number_b or $number_c but that doesn't work. Any ideas?
As mentioned before, you can use the mod (%) function to do that.
Basically what it does is to get the remainder after division. So, if you say 11 % 3, you will get 2 since that is the remainder after division. You can then make use of this to check when a number is divisible by 3 (the remainder will be zero), and insert an end </div> in your code.
Here is a simplified example on how to use it to insert a newline after every 3 columns:
$cycle = 1;
$arr = range (1, 20);
$len = sizeof ($arr);
for ( ; $cycle <= $len; $cycle++)
{
echo "{$arr[$cycle - 1]} ";
if ($cycle % 3 == 0)
{
echo "\n";
}
}
echo "\n\n";

Categories