taking the latest content from a dynamic array - php

A small background of myself is that I'm fairly new to php. I work as an IT assistant and have been asked to edit one of the pages our designers use for samples. I cannot point you to the page as it is an internally hosted page.
I'm honestly not even sure if the question is asked correctly but please bear with me.
The page has a 'request completion date' field within a table that outputs 6 dates in a list, the designers only want it to output the latest date from that list instead of all 6, usually these will be empty so it's no use having them printed.
The code to put them is as follows;
if ($database_data['request_confirmed_comp_date'] > "0")
{ $request_confirmed_completion_date = date("d/m/Y", $database_data['request_confirmed_comp_date']); }
else
{ $request_confirmed_completion_date = " -"; }
if $database_data['request_confirmed_comp_date2'] > "0")
{
$request_confirmed_completion_date2 = date("d/m/Y", $database_data['request_confirmed_comp_date2']);
}
else
{
$request_confirmed_completion_date2 = " -";
}
if ($database_data['request_confirmed_comp_date3'] > "0")
{
$request_confirmed_completion_date3 = date("d/m/Y", $database_data['request_confirmed_comp_date3']);
}
else
{
$request_confirmed_completion_date3 = " -";
}
if ($database_data['request_confirmed_comp_date4'] > "0")
{
$request_confirmed_completion_date4 = date("d/m/Y", $database_data['request_confirmed_comp_date4']);
}
else
{
$request_confirmed_completion_date4 = " -";
}
if ($database_data['request_confirmed_comp_date5'] > "0")
{
$request_confirmed_completion_date5 = date("d/m/Y", $database_data['request_confirmed_comp_date5']);
}
else
{
$request_confirmed_completion_date5 = " -";
}
if ($database_data['request_confirmed_comp_date6'] > "0")
{
$request_confirmed_completion_date6 = date("d/m/Y", $database_data['request_confirmed_comp_date6']);
}
else
{
$request_confirmed_completion_date6 = " -";
}
if ($database_data['request_date_required'] > "0")
{
$request_date_required = date("d/m/Y", $database_data['request_date_required']);
}
else
{
$request_date_required = "-";
}
if ($database_data['request_date'] > "0")
{
$request_date = date("d/m/Y", $database_data['request_date']);
}
else
{
$request_date = "-";
}
It is then called into play using;
echo '<td><b>1.</b>'.$request_confirmed_completion_date.'<br /><b>2.</b>'.$request_confirmed_completion_date2.'<br /><b>3.</b>'.$request_confirmed_completion_date3.'<br /><b>4.</b>'.$request_confirmed_completion_date4.'<br /><b>5.</b>'.$request_confirmed_completion_date5.'<br /><b>6.</b>'.$request_confirmed_completion_date6.'</td>';
Now I may not have much php knowledge, but I know that's a horribly long way of doing that. Is there anyway that I could pull the latest date out of an array, created by the the first block of code, and then output them into the table.
Thanks for any help or advice, even if you could just point me in the right direction as to what loop to use would be helpful.
Edit: I've uploaded the full file online here, hopefully that will clear up some confusion.

You want to use the php function asort. Since all of your values look to be numeric, you should be able to do a standard sort and pull off the last item with array_pop.
It might look something like this:
asort($database_data);
$latest = array_pop($database_data);
echo date('m/d/Y', $latest);

Create an array with the variable names, like if the variables are $A, $B and $C, then
$vars = array("A","B","C");
foreach($vars as $var_name){
if($database_data[$var_name] > "0")
$$var_name = $database_data[$var_name];
else
$$var_name = "-";
}
Note: A, B and C are dummy variable names, as the variable names are too long in your code :-)

Firstly there is a problem with your if conditions, you can't say $x > "0" because with using double-quotes you are using 0 as a string. You should use integer $x > 0.
Now here my answer :
I couldn't understand your system very well, so i'm assuming always there will be 6 dates.
for($q = 0;$q < 6; $q++)
{
if($database_data[...][$q] > 0)
$dates[] = date("d/m/Y", $database_data['...'][$q]);
else
$dates[] = " - ";
}
As you see, you have to fetch your database datas as an array $database_data['...'][].

If you can tweak the original SQL statement, which probably looks something like this:
select request_confirmed_comp_date, request_confirmed_comp_date2, request_confirmed_comp_date3, request_confirmed_comp_date4, request_confirmed_comp_date5, request_confirmed_comp_date6
from sometablename
where somefield='something'
You can tweak it to use shorter (and consistent) field names
select request_confirmed_comp_date as date1, request_confirmed_comp_date2 as date2, request_confirmed_comp_date3 as date3, request_confirmed_comp_date4 as date4, request_confirmed_comp_date5 as date5, request_confirmed_comp_date6 as date6
from sometablename
where somefield='something'
And then in PHP use an array to iterate over the field names like so:
<?php
$lastCompletionDate=""; //start by assuming there was no completion date
for($i=1;$i<=6;$i++) { //check to see if any field is after the last known completion date
if ($database_data['date'.$i] && (date("d/m/Y", $database_data['date'.$i]) > $lastCompletionDate)) {
//if so, store the new date
$lastCompletionDate=date("d/m/Y", $database_data['date'.$i]);
}
}
if($lastCompletionDate) {
echo "The last completion date was $lastCompletionDate\n";
}else {
echo "There was no completion date.\n";
}
?>

An alternative solution would be to use the SQL engine's own internal functions to find the highest date like so:
select greatest(request_confirmed_comp_date,
request_confirmed_comp_date2,
request_confirmed_comp_date3,
request_confirmed_comp_date4,
request_confirmed_comp_date5,
request_confirmed_comp_date6) as greatestcompdate
from sometablename etc...
and then refer to that in PHP like
<?php
if($database_data['greatestcompdate']) {
echo "There was a greatest completion date and it was $database_data[greatestcompdate]";
}
?>

Related

PHP: detect end of duplicate column results (calendar day)

I've been putting together a simple linear weekly event calendar script, which calls entries from a MYSQL database. It displays a sort of "8 day week" (Sunday to Sunday inclusive)
My MYSQL query is like so:
$results = $dbh->query('SELECT * FROM calendar WHERE YEARWEEK(event_date) = YEARWEEK(NOW()) OR (WEEKDAY(event_date) = 6 AND YEARWEEK(event_date) = YEARWEEK(NOW()) + 1) ORDER BY event_date ASC');
When a given day has multiple event entries, I keep the day/date heading from repeating:
$currentday = '';
$showday = true;
foreach($results as $row) {
$weekday = date("l", strtotime($row['event_date'])); {
if ($currentday != $row['event_date']) {
$showday = true;
$currentday = $row['event_date'];
}
if ($showday) {
$weekday = date("l", strtotime($row['event_date']));
if($weekday == "Sunday") {
echo "<h3 class='sunday'>";
echo $weekday;
}
else {
echo "<h3>";
echo $weekday;
}
echo date("F j", strtotime($row['event_date']));
$showday = false;
}
}
... followed by the remaining details.
All that works great.
What I'm trying to accomplish now is to group each day's results visually by means of an HTML hook.
To accomplish that, I'm trying to group each day's events within a div with a class of "daybox". I can create/open the div with this, just after the first if clause:
if ($showday) { ?><div class="daybox">
That successfully opens/create a new div for each distinct day of the foreach loop.
The problem is closing it. I tried a corresponding if $showday closing code at the end of my foreach, but in retrospect, that wasn't what I was looking for, and obviously it didn't work.
What I think I need is a way to determine whether I've reached the last entry for a given day (i.e. event_date in my database), and base my if clause off that. But so far I'm stumped how I need to articulate that.
Am I on the right track, and how would I formulate my final if clause?
Thanks!
Well, this isn't a real PHP solution, but I found a workaround that I can live with.
I changed this line:
if ($showday) { ?><div class="daybox">
to this:
if ($showday) { echo "</div><div class='daybox'>"; }
That gives me an anomalous closing div tag before the first day of the calendar, but I reconciled my HTML by placing an opening div tag outside of my foreach loop. (In my case, I already had an h2 for a "This Week" title, so now I've got the heading wrapped in a div.)
This works for this particular use case, but if somebody has the proper PHP answer, please feel free to provide.
My friend Anthony, who is a hardcore programmer, although not really a PHP guy, provided the actual code to accomplish this properly.
Below the $weekday = date ... line, the code above has been replaced with this:
if ($currentDay != $weekday) {
if ($currentDay != '') {
echo "</div>";
}
$currentDay = $weekday;
$showday = true;
echo "<div class='daybox'>";
}
?>
<section class="calendar-item">
<?php
if ($showday) {
if ($weekday == "Sunday") {
echo "<h3 class='sunday'>";
} else {
echo "<h3>";
}
echo $weekday;?>
</h3><p class="date-detail"><?php
echo date("F j", strtotime($row['event_date'])); ?></p><?php
$showday = false;
}
Works a treat. Now I need to study it in order to fully grasp how he did it.

PHP how to convert date from different language

I'm beginner in php, I really need help, I have a question everybody help me please, I'm making a scraping data, from other website,the website have data like 07 Ogos 2015. when I write this in controller
public function UMKDATA()
{
$data = array();
$this->load->library('simple_html_dom');
$this->load->model('Vtender_Data');
// create HTML DOM
$html = file_get_html("http://www.umk.edu.my/index.php/en/component/k2/item/180-tender-dan-sebutharga");
// get title
$strA = $html->find('.itemFullText tbody tr');
$j = 0;
foreach($strA as $strB)
{
if($j >= 1)
{
$strB->innertext;
$strC = str_get_html($strB->innertext);
$masuk['Title'] = str_get_html($strB->find('td',1)->innertext)->find('span',0)->plaintext;
if($this->Vtender_Data->check($masuk['Title']) == 0)
{
$masuk['source'] = $strC->find('td',0)->plaintext;
// $masuk['Opening_Date'] = $strC->find('td',2)->plaintext;
$masuk['Posted_Date'] = date('y-m-d', strtotime($strC->find('td',3)->innertext));
//$masuk['Posted_Date'] = $strC->find('td',3)->plaintext;
$masuk['Document'] = str_get_html($strC->find('td',4)->innertext)->find('a',0)->href;
$masuk['URLNAME'] = 'UMK' ;
$this->Vtender_Data->masuk($masuk);
}
}
$j++;
}
}
Date Posted_Date in my db look like this 1970-01-01, what should I do? I have to change the language or what, so that data in db correct and look like 2015-08-09.
You have to write:
date("Y-m-d H:i:s");
Y means: A full numeric representation of a year, 4 digits
y means: A two digit representation of a year
look at: http://php.net/manual/en/function.date.php

php date_parse("Feb 2010") gives day == 1

There is what I would call a bug in date_parse when there is no day. $d = date_parse("Feb 2010") will give $d["day"] == 1.
See the comment on this on the date_parse manual page.
Any nice workaround for this problem? :-)
UPDATE
The date comes from published research reports. Unfortunately this means that they could look in different ways. I want to convert them to more standard ISO format when displaying the references. To help the readers I want always to include just the given fields (years, month, date). So this should be valid (and just give me the year):
2010
This should be valid, but just give me 2010-02 so to say:
Feb 2010
UPDATE 2
So far I have seen two bugs here in date_parse. It can't parse 2010. And it gives a day though there is no day in Feb 2010.
I can of course write a fix for this, but surely someone has already done this, or???
The above bugfix routine is great, Leo, thanks. Unfortunately it still trips over January, thinking that 2014-01 is the same as 2014-01-01 --- we're eleven-twelfths of the way there.
The date formats that PHP can parse, that don't contain a day-of-month, appear to be (in php_src:date/lib/parse_date.re):
gnudateshorter = year4 "-" month;
datenoday = monthtext ([ .\t-])* year4;
datenodayrev = year4 ([ .\t-])* monthtext;
Very few, conveniently. We can run the same regexes on $dateRaw, essentially reverse-engineering what the parser had decided.
(Side observations: the above excludes formats like 5/2016, which is parsed as "20 May with some extra characters at the end"; they are also similar to day-of-year and week-of-year formats, so we'll try not to trip over those.)
function date_parse_bugfix($dateRaw) {
$dateRaw = trim($dateRaw);
// Check for just-the-year:
if (strlen($dateRaw) === 4 && preg_match("/\d{4}/", $dateRaw) === 1) {
$da = date_parse($dateRaw . "-01-01");
$da["month"] = false;
$da["day"] = false;
}
else {
$da = date_parse($dateRaw);
if ($da) {
// If we have a suspicious "day 1", check for the three formats above:
if ($da["day"] === 1) {
// Hat tip to http://regex101.com
// We're not actually matching to monthtext (which is looooong),
// just looking for alphabetic characters
if ((preg_match("/^\d{4}\-(0?[0-9]|1[0-2])$/", $dateRaw) === 1) ||
(preg_match("/^[a-zA-Z]+[ .\t-]*\d{4}$/", $dateRaw) === 1) ||
(preg_match("/^\d{4}[ .\t-]*[a-zA-Z]+$/", $dateRaw) === 1)) {
$da["day"] = false;
}
}
}
}
return $da;
}
No answers so I answer my own question. Here is a workaround the problems I saw.
// Work around for some bugs in date_parse (tested in PHP 5.5.19)
// http://php.net/manual/en/function.date-parse.php
//
// Date formats that are cannot be parsed correctly withoug this fix:
// 1) "2014" - Valid ISO 8061 date format but not recognized by date_parse.
// 2) "Feb 2010" - Parsed but gives ["day"] => 1.
function date_parse_5_5_bugfix($dateRaw) {
// Check "2014" bug:
$dateRaw = rtrim($dateRaw);
$dateRaw = ltrim($dateRaw);
if (strlen($dateRaw) === 4 && preg_match("/\d{4}/", $dateRaw) === 1) {
$da = date_parse($dateRaw . "-01-01");
$da["month"] = false;
$da["day"] = false;
} else {
$da = date_parse($dateRaw);
if ($da) {
if (array_key_exists("year", $da)
&& array_key_exists("month", $da)
&& array_key_exists("day", $da))
{
if ($da["day"] === 1) {
// Check "Feb 2010" bug:
// http://www.phpliveregex.com/
if (preg_match("/\b0?1(?:\b|T)/", $dateRaw) !== 1) {
$da["day"] = false;
}
}
}
}
}
return $da;
}
Some tests (visual ;-) )
$a = date_parse_5_5_bugfix("2014"); print_r($a);
$b = date_parse_5_5_bugfix("feb 2010"); print_r($b);
$c = date_parse_5_5_bugfix("2014-01-01"); print_r($c);
$d = date_parse_5_5_bugfix("2014-11-01T06:43:08Z"); print_r($d);
$e = date_parse_5_5_bugfix("2014-11-01x06:43:08Z"); print_r($e);
Can you try:
$dateTime = strtotime('February, 2010');
echo date('Y-m', $dateTime);

How to manage couple of combo box working together?

I'm having two comboboxes. One is like 'admin', 'city' , 'theatre' and the other one is daily and weekly. If user select one of item in first and daily in second it shows daily operations. If user select one of item in the first one select nothing in second one it shows daily and weekly operations. If user does not select anything in first and daily in second it brings all operations daily and son on.
Therefore I think there is 2^3 if conditions. Is there anyway to reduce this? I am using PHP language but I think core algorithm is same in all languages!
Following is what I have done so far for three conditions if it is admin and daily and weekly:
<?php
if(strlen($_POST['attribute'])>0)
{
echo "For admin: ";
echo "</br>";
//If admin
if($_POST['attribute'] == 'Admin'){
//If daily
if($_POST['date'] == 'Daily'){
echo "The only feature to show update is making a user admin\n";
echo "</br>";
$fh = fopen('back-up/makeadmin.txt','r');
$foo = true;
while ($line = fgets($fh)) {
if($foo){
//Current time
$now = new DateTimeImmutable();
//One week ago
$oneDayAgo = $now->sub(new DateInterval('P1D'));
echo "</br>";
echo "</br>";
$date = DateTime::createFromFormat('m/d/Y h:i:s a+', $line);
//Here you can compare your dates like any other variables
if ($date > $oneDayAgo) {
/* Nothing echo "Current date is less than 1 week old";
Break;
*/
break;
}
if ($date < $oneDayAgo) {
echo "$line";
}
var_dump($line);
}
$foo = (!$foo);
}
fclose($fh);
}
else { /*if($_POST['date'] == 'Weekly'){*/
echo "The only feature to show update is making a user admin\n";
echo "</br>";
$fh = fopen('back-up/makeadmin.txt','r');
$foo = true;
while ($line = fgets($fh)) {
if($foo){
//Current time
$now = new DateTimeImmutable();
//One week ago
$oneWeekAgo = $now->sub(new DateInterval('P1W'));
echo "</br>";
echo "</br>";
$date = DateTime::createFromFormat('m/d/Y h:i:s a+', $line);
//Here you can compare your dates like any other variables
if ($date > $oneWeekAgo) {
/* Nothing echo "Current date is less than 1 week old";
Break;
*/
}
if ($date < $oneWeekAgo) {
echo "Current date is more than 1 week old";
}
var_dump($line);
}
$foo = (!$foo);
}
fclose($fh);
}
//If not daily
else
{
echo "weekly";
}
}
}
else
{
echo "Not admin";
}
?>
I'm not familiar with PHP, but if your code has a lot of hard-coded if statements, it's a clear sign that you need a better data structure, or maybe any data structure at all.
For example, you duplicate a whole block of code that only differs in that the first uses $oneDayAgo and the second $oneWeekAgo?. You could easily make that into a variable someTimeAgo that is a time span of seven days or one day, depending on the value of your second list box.
I'm not sure what the selection of the first box is for, maybe the file to read from? You might be able to find some common behaviour fro these three cases, too, and try to express them in variables rather than code.
You could probably store the relevant data is an associative array whose keys are the values of the list boxes:
$span = array("Daily" => "P1D", "Weekly" => "P1W");
As a next step, you could even populate your list from PHP with the keys (the values left of the fat arrows) of the array and you could easily extens the list together with the time spans without adding any new code, just new data.
Lastly, an UI niggle: If you have only two values, you shouldn't use a drop-down list box. Use a group of two radio-buttons next to each other and the user will be able to see both options at one glance without having to click anything. (I also don't think these are combo boxes, because combo boxes allow to enter a value by either typing it in manually or selecting it from a drop-down list.)

php foreach inside for statement problems

Sorry if this has been asked before however I am having trouble finding the answer to my problem.
I am trying to build a calendar system and schedule system for my web application in PHP and having difficulty with one particular area.
I have a "for" statement where it will draw up the times of the day starting at 12:00AM and finishing at 11:30PM
Inside this for loop, I have a foreach which i want to echo out the objects in an array that match a particular time.
Everything I have tried which includes using for,while and foreach statements don't show what I am after which is the events lining up next to the time.
here is my code
<?php
$tStart = strtotime($start_time);
$tEnd = strtotime($end_time);
$tNow = $tStart;
while($items = mysql_fetch_object($result)){
$events[] = $items;
}
for($tNow=$tStart; $tNow<$tEnd; $tNow=strtotime('+30 minutes',$tNow)){
// Time to color the rows to make it easier to read
if(!isset($day_row)){
$day_row = "0";
}
if(isset($day_row) && $day_row >= "2"){
$day_row--;
}
else{ $day_row++;
}
//This bit draws the first column.
echo "<tr><td class=\"day_row".$day_row."\" width=\"70px\">".date("h:i A",$tNow)."</td>";
// MySQL stuff is now here
foreach($events as $e => $item){
if($item->apnt_start == $tnow){
$rowspan = ((strtotime($item->apnt_finish)-strtotime($item->apnt_start))/"1800");
echo "<td class=\"day_row_apnt\" rowspan=\"$rowspan\">".$item->apnt_start."-".$item->apnt_finish." ".$item->apnt_brief."</td></tr>";
}
}
}
?>
at present i am given a page with
12:00 AM
12:30 AM
01:00 AM
01:30 AM
02:00 AM
02:30 AM
03:00 AM
03:30 AM
04:00 AM
04:30 AM
05:00 AM
05:30 AM
Next to the time I want the appointment with matching time.
I am trying to achieve something similar to http://mrbs.sourceforge.net/
I can't use their system however as I can't integrate it properly and I have tried looking at their code and it seems to be pointing at many files and i am having trouble trying to understand the function i am after.
Please let me know if this is not clear enough and will try to explain further.
You need to define and set value for variables below:
$start_time = "09:00 AM";
$end_time = "11:30 PM";
Also you need to add query and database connection (above while($items = mysql_fetch_object($result)){ statement):
mysql_connect("hostname", "user", "password");
mysql_select_db("mydb");
$result = mysql_query("select * from mytable");
EDIT:
You should use while mysql_fetch_assoc instead of mysql_fetch_object.
Replace
while($items = mysql_fetch_object($result)){
with
while($items = mysql_fetch_assoc($result)){
Delete: $events[] = $items;
Ensure your while statement above ends after all code is executed (code you listed in your question) - closing bracket }.
Okay, this should work for you.
<?php
$tStart = strtotime($start_time);
$tEnd = strtotime($end_time);
$tNow = $tStart;
echo '<table>';
while($events = mysql_fetch_assoc($result)){
for($tNow=$tStart; $tNow<$tEnd; $tNow=strtotime('+30 minutes',$tNow)){
// Time to color the rows to make it easier to read
if(!isset($day_row)){
$day_row = "0";
}
if(isset($day_row) && $day_row >= "2"){
$day_row--;
}
else{ $day_row++;
}
//This bit draws the first column.
echo "<tr><td class=\"day_row".$day_row."\" width=\"70px\">".date("h:i A",$tNow)."</td>";
if(strtotime($events['apnt_start']) == $tNow) {
$rowspan = ((strtotime($events->apnt_finish)-strtotime($events->apnt_start))/"1800");
echo "<td class=\"day_row_apnt\" rowspan=\"$rowspan\">".$events->apnt_start."-".$events->apnt_finish." ".$events->apnt_brief."</td></tr>";
}
} //end for
} //end while
echo '</table>';
?>
I would like to thank everyone that provided advice on this issue, I have finally got it working with added another variable and using a method of storing an array in an array.
The final code looks like
<?php
$tStart = strtotime($start_time);
$tEnd = strtotime($end_time);
$tNow = $tStart;
$events = array();
$eas = "0"; // eas stands for Event Array Start. this will be used to cycle through the events in the array.
while($items = mysql_fetch_assoc($result)){
$events[] = $items;
}
for($tNow=$tStart; $tNow<$tEnd; $tNow=strtotime('+30 minutes',$tNow)){
// Time to color the rows to make it easier to read
if(!isset($day_row)){
$day_row = "0";
}
if(isset($day_row) && $day_row >= "2"){
$day_row--;
}
else{ $day_row++;
}
//This bit draws the first column.
echo "<tr><td class=\"day_row".$day_row."\" width=\"70px\">".date("h:i A",$tNow)."</td>";
if(strtotime($events[$eas]['apnt_start']) == $tNow) {
$rowspan = ((strtotime($events[$eas]['apnt_finish'])-strtotime($events[$eas]['apnt_start']))/"1800");
echo "<td class=\"day_row_apnt\" rowspan=\"$rowspan\" >".$events[$eas]['apnt_start']."-".$events[$eas]['apnt_finish']." ".$events[$eas]['apnt_brief']."</td></tr>";
$eas++;
}
else{
echo "<td class=\"day_row".$day_row."\"></td>";
}
} //end for
?>
By using the variable $eas I was able to then control which number it would start at by setting it to 0 initially and then when it found an entry with a matching time it went through the if statement where at the end of the if statement it was given $eas++ to increment.
This then proved that if there was no appointment the $eas would not run and it would not increment thus remaining on the last incremented $eas.
Thanks again for everyone's help.

Categories