Pagination: the logic? - php

Im making a pagination system that will paginate articles in my website.
GOAL: Paginate an array of files (7 element/page)
I got across a problem that ive been troubleshooting for 5+ hours... Heres the logic side of things, correct me if im wrong.
Okay. So ive got 26 dummy articles (the alphabet) inside a folder.
Lets find the number of files in there... I will call the result: variable X.
To get the number of pagination pages, im doing the following:
X divided by 7. Obviously, this can output floats instead of integers.. So ill be rounding up the result using "cint"- which will always round upwards.
Lets call the number of pages "Z".
So me and my new friend Z want to tell some kind of function to fetch those articles. Ive made the following equations to find the start and the end of what articles I want to show.
$start = Z * 7 - 7
$end = Z * 7
Those equations generate
0 to 7 for page 1. Expected result (not reality):
a, b, c, d, e, f, g.
8 to 15 for page 2. Expected result (not reality).
h, i, j, k, l, m, n.
And so on...
So, using my superior brain (sike) I managed to generate the following output for page 1:
CHOOSE PAGE: 1 2 3 4
Youre at page 1
Theres 26 articles
Showing 0 to 7
a - Thursday, 4th of April 2019 # 20:54:02
b - Thursday, 4th of April 2019 # 20:54:04
c - Thursday, 4th of April 2019 # 20:54:08
d - Thursday, 4th of April 2019 # 20:54:10
e - Thursday, 4th of April 2019 # 20:54:13
f - Thursday, 4th of April 2019 # 20:54:15
g - Thursday, 4th of April 2019 # 20:54:18
But, wierdly enough, when I go to page 2, I get... this mess.
CHOOSE PAGE: 1 2 3 4
Youre at page 2
Theres 26 articles
Showing 7 to 14
h - Thursday, 4th of April 2019 # 20:54:22
i - Thursday, 4th of April 2019 # 20:54:24
j - Thursday, 4th of April 2019 # 20:54:28
k - Thursday, 4th of April 2019 # 20:54:31
l - Thursday, 4th of April 2019 # 20:54:34
m - Thursday, 4th of April 2019 # 20:54:37
n - Thursday, 4th of April 2019 # 20:54:39
o - Thursday, 4th of April 2019 # 20:54:42
p - Thursday, 4th of April 2019 # 20:54:44
q - Thursday, 4th of April 2019 # 20:55:47
r - Thursday, 4th of April 2019 # 20:55:49
s - Thursday, 4th of April 2019 # 20:55:51
t - Thursday, 4th of April 2019 # 20:55:53
u - Thursday, 4th of April 2019 # 20:55:55
...And when I go to page 3, some of the results from page 2 appears!
CHOOSE PAGE: 1 2 3 4
Youre at page 3
Theres 26 articles
Showing 14 to 21
o - Thursday, 4th of April 2019 # 20:54:42
p - Thursday, 4th of April 2019 # 20:54:44
q - Thursday, 4th of April 2019 # 20:55:47
r - Thursday, 4th of April 2019 # 20:55:49
s - Thursday, 4th of April 2019 # 20:55:51
t - Thursday, 4th of April 2019 # 20:55:53
u - Thursday, 4th of April 2019 # 20:55:55
v - Thursday, 4th of April 2019 # 20:55:57
w - Thursday, 4th of April 2019 # 20:56:00
x - Thursday, 4th of April 2019 # 20:56:03
y - Thursday, 4th of April 2019 # 20:56:05
z - Thursday, 4th of April 2019 # 20:56:07
Finally, I get one last page (page 4) with the final last result from page 3.
Heres the code...
<?php
$page = strip_tags($_GET['p']);
if(empty($page)){$page = "1";}
$post_array = glob("post/*");
$post_count = count($post_array);
$page_num = ceil($post_count / 7);
echo "CHOOSE PAGE: ";
for($i = 1; $i<$page_num+1; $i++){
echo "{$i} ";
}
if($page>$page_num){
echo "<br>error";
}
elseif(!is_numeric($page)) {
echo "<br>error";
}
else {echo "<br>Youre at page {$page}<br>";
echo "Theres {$post_count} articles<br><br>";
$start = $page * 7 - 7;
$end = $page * 7;
$post_array_sliced = array_slice($post_array, $start, $end);
echo "Showing {$start} to {$end}<br><br>";
foreach ($post_array_sliced as $post){
$post_name = pathinfo($post)['filename'];
$post_date = filemtime($post);
echo "{$post_name} - ".date('l, jS \of F Y # H:i:s', $post_date)."<br>";
}
}
?>
I think this problem is caused by my awful logic skills.
Could anyone correct me, point me to docs?
Thanks alot for yall time :)

array_slice doesn't expect the first and the last index, but the first index and the length (number of elements to extract).
So you should put:
array_slice($post_array, $start, 7);

Related

PHP date() as MySQL YEARWEEK()

This question is pretty similar to this and this (and other) questions, but what I want to do is the opposite, I am expecting a PHP answer to show the same result than MySQL YEARWEEK().
Today is 2019-09-16 and MySQL YEARWEEK says:
SELECT YEARWEEK(NOW()) -- returns 201937
And PHP says:
echo date('oW') // returns 201938
What do I have to do in PHP to show "201937" just like MySQL YEARWEEK does?
There are two issues:
The weeks number changes on different days (Monday for PHP, Sunday for MySQL)
The first week of the year is determined differently (week containing the 4th of january for PHP, week starting with the first Sunday of the year for MySQL)
Which then causes these differences:
First day of year: | Mo | Tu | We | Th | Fr | Sa | Su |
PHP week | ------- 01 ------ | --- 52/53 -- |
MySQL week | ----------- 52/53 ----------| 01 |
We have 2 different cases, based on when the year starts:
If it starts a Friday, Saturday or Sunday, PHP start week 1 "late" by 1 day (it can be solved by taking tomorrow's week number in PHP)
It it starts a Monday, Tuesday, Wednesday or Thursday, you'll end up with an offset of 3-6 days, PHP being ahead this time, and it becomes a mess to solve.
So all in all, it seems you're better off just counting how many Sundays already passed this year, which apparently can be done with the following (adapted from this):
ceil((date("z") + 1 - date("w")) / 7); //added +1 in case the year starts a Sunday
And if it's 0 you count how many Sundays there were last year:
$ldly = strtotime(date("Y")-1)."-12-31"); //last day last year
ceil((date("z", $ldly ) + 1 - date("w", $ldly )) / 7);
By combining the two (and adding a parameter if you want to check dates other than today) you'd get:
function weekNum($date = false) {
$day = $date ? strtotime($date) : time();
if($res = ceil((date("z", $day) + 1 - date("w", $day)) / 7)){
return $res;
}
$ldly = strtotime((date("Y", $day)-1)."-12-31"); //last day last year
return ceil((date("z", $ldly ) + 1 - date("w", $ldly )) / 7);
}
I think this should always match with the MySQL date, but do your own tests to make sure! :)
Like this?
echo date('oW', time() - 86400); // basically use yesterday's week number

Adding and removing from a string containing dates using PHP

I have to edit a whole bunch of date intervals. But they are all mixed up. Most are in the form Month YearMonth Year
eg January 2014March 2015
How would I insert a hyphen in between so I end up with
January 2014 - March 2015
I also have the problem where these dates occur in the same year.
eg April 2012September2012
In such a case I would need to insert the hyphen and remove the year so that I'm left with
April - September
There must be some PHP string operators for stuff like this. Well thats what I'm hoping.
Would appreciate some guidance. Thanks in advance.
Thanks, sorry for my delayed reply
$string = "January 2014March 2015";
preg_match('/([a-z]+) *(\d+) *([a-z]+) *(\d+)/i', $string, $match);
print "$match[1] $match[2] - $match[3] $match[4]";
outputs,
January 2014 - March 2015
You could do it using lookaround:
$string = "January 2014March 2015";
$res = preg_replace('/(?<=\d)(?=[A-Z])/', ' - ', $string);
echo $res,"\n";
Output:
January 2014 - March 2015

Extract dates, times and date ranges from text in PHP

I'm building a local events calendar which takes RSS feeds and website scrapes and extracts event dates from them.
I've previously asked how to extract dates from text in PHP here, and received a good answer at the time from MarcDefiant:
function parse_date_tokens($tokens) {
# only try to extract a date if we have 2 or more tokens
if(!is_array($tokens) || count($tokens) < 2) return false;
return strtotime(implode(" ", $tokens));
}
function extract_dates($text) {
static $patterns = Array(
'/^[0-9]+(st|nd|rd|th|)?$/i', # day
'/^(Jan(uary)?|Feb(ruary)?|Mar(ch)?|etc)$/i', # month
'/^20[0-9]{2}$/', # year
'/^of$/' #words
);
# defines which of the above patterns aren't actually part of a date
static $drop_patterns = Array(
false,
false,
false,
true
);
$tokens = Array();
$result = Array();
$text = str_word_count($text, 1, '0123456789'); # get all words in text
# iterate words and search for matching patterns
foreach($text as $word) {
$found = false;
foreach($patterns as $key => $pattern) {
if(preg_match($pattern, $word)) {
if(!$drop_patterns[$key]) {
$tokens[] = $word;
}
$found = true;
break;
}
}
if(!$found) {
$result[] = parse_date_tokens($tokens);
$tokens = Array();
}
}
$result[] = parse_date_tokens($tokens);
return array_filter($result);
}
# test
$texts = Array(
"The focus of the seminar, on Saturday 2nd February 2013 will be [...]",
"Valentines Special # The Radisson, Feb 14th",
"On Friday the 15th of February, a special Hollywood themed [...]",
"Symposium on Childhood Play on Friday, February 8th",
"Hosting a craft workshop March 9th - 11th in the old [...]"
);
$dates = extract_dates(implode(" ", $texts));
echo "Dates: \n";
foreach($dates as $date) {
echo " " . date('d.m.Y H:i:s', $date) . "\n";
}
However, the solution has some downsides - for one thing, it can't match date ranges.
I'm now looking for a more complex solution that can extract dates, times and date ranges from sample text.
Whats the best approach for this? It seems like I'm leaning back toward a series of regex statements run one after the other to catch these cases. I can't see a better way of catching date ranges in particular, but I know there must be a better way of doing this. Are there any libraries out there just for date parsing in PHP?
Date / Date Range samples, as requested
$dates = [
" Saturday 28th December",
"2013/2014",
"Friday 10th of January",
"Thursday 19th December",
" on Sunday the 15th December at 1 p.m",
"On Saturday December 14th ",
"On Saturday December 21st at 7.30pm",
"Saturday, March 21st, 9.30 a.m.",
"Jan-April 2014",
"January 21st - Jan 24th 2014",
"Dec 30th - Jan 3rd, 2014",
"February 14th-16th, 2014",
"Mon 14 - Wed 16 April, 12 - 2pm",
"Sun 13 April, 8pm",
"Mon 21 - Wed 23 April",
"Friday 25 April, 10 – 3pm",
"The focus of the seminar, on Saturday 2nd February 2013 will be [...]",
"Valentines Special # The Radisson, Feb 14th",
"On Friday the 15th of February, a special Hollywood themed [...]",
"Symposium on Childhood Play on Friday, February 8th",
"Hosting a craft workshop March 9th - 11th in the old [...]"
];
The function I'm currently using (not the above) is about 90% accurate. It can catch date ranges, but has difficulty if a time is also specified. It uses a list of regex expressions and is very convoluted.
UPDATE: Jan 6th, 2014
I'm working on code that does this, working on my original method of a series of regex statements run one after the other. I think I'm close to a working solution that can pretty much extract almost any date/time range / format from a piece of text. When I'm done I'll post it here as an answer.
I think you can sum up the regex in your question like the one below.
(?<date_format_1>(?<day>(?i)\b\s*[0-9]+(?:st|nd|rd|th|)?)(?<month>(?i)\b\s*(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|etc))(?<year>\b\s*20[0-9]{2}) ) |
(?<date_format_2>(?&month)(?&day)(?!\s+-)) |
(?<date_format_3>(?&day)\s+of\s+(?&month)) |
(?<range_type_1>(?&month)(?&day)\s+-\s+(?&day))
Flags: x
Description
Demo
http://regex101.com/r/wP5fR4
Discussion
By using recursive subpatterns, you reduce the complexity of the final regex.
I have used a negative lookahead in the date_format_2 because it would match partially range_type_1. You may need to add more range type depending on your data. Don't forget to check other partterns in case of partial match.
Another solution would consist in build small regexes in different string variables and then concatenate them in PHP to build a bigger regex.

Difference between 2 dates in quarters

I am trying to make a function that gives me the number of quarters between 2 dates as an integer. The dates passed to the function are usually quarter-end dates except occasionally when one of the dates is just an arbitary date.
Basically I want it to figure out what quarter the two dates fall into and give an integer difference in the number of quarters.
E.g.
Q1 2013 -> Q2 2013 = 1
Q1 2013 -> Q4 2013 = 3
Q2 2012 -> Q2 2013 = 4
Q4 2012 -> Q1 2013 = 1
Here is my function. I realise it is poor and does not return the correct answer all the time but I'm hoping someone can help...
function quarter_diff(DateTime $d1, DateTime $d2){
//difference in months
$diff = $d1->diff($d2);
return ceil((($diff->format('%y') * 12) + $diff->format('%m')+1)/4);
}
and a fiddle here: http://phpfiddle.org/lite/code/tiw-jx3
We can see theat when the date is in the month after the end of a quarter we don not get the correct answer.
Can anyone suggest an improvement??
Convert each of your dates into quarters, then do the math, much like your first example.
Some quick pseudocode:
Convert d1 to quarter and year -> d1.quarter and d1.year
Convert d2 to quarter and year -> d2.quarter and d2.year
Number of quarters = d1.quarter - d2.quarter + (d1.year - d2.year)*4
Use the absolute value of the result to get the number of quarters difference.
You can create a quick and dirty "quarter" function by dividing month-1 by 3 and adding 1 to the integer portion of the result. Assuming January = 1, December = 12 and Q1 = January through March. You'll have to make adjustments if Q1 starts elsewhere, such as July.
Q = (int)(month - 1)/3 + 1
or
Q = ceiling(month/3)
This is what I opted for thanks to suggestion from Maple
function quarter_diff(DateTime $d1, DateTime $d2){
//Returns the number of quarters between two dateTime objects
if ($d2 > $d1){
$dtmp = $d1;
$d1=$d2;
$d2=$dtmp;
unset($dtmp);
}
$d1q = ceil($d1->format('m')/3);
$d2q = ceil($d2->format('m')/3);
$d1y = $d1->format('y');
$d2y = $d2->format('y');
return $d1q - $d2q + 4*($d1y - $d2y);
}
in MYSQL:
SELECT (year('2016-06-30') - year('2015-07-01'))*4 + quarter('2016-06-30') - quarter('2015-07-01') + 1

Need to display mysql table ordered by date but separated by week

I'm using PHP and MySQL. I have a page that displays meetings created by people with a link to view details. Right now I'm using just a simple table to display everything sorted by date. The table in the database is called 'meetings' and there are 3 columns -
'meetingid' (int)
'time' (datetime)
'creator' (text)
My problem is that it looks a little messy and difficult to read when there are quite a few meetings created since they are all in just one big clump. I'd like to split them up by week (starting Monday, ending Sunday - or Sunday-Saturday if that's easier). I've linked to a doc at the bottom showing what I currently have (first page) and something more like what I want (second page). The week labels (ex. September 3rd - September 9th) would need to only go on for as long as there are meetings booked. So, if the latest meeting is October 7th then the last week shown should be 'October 1st - October 7th'. Figuring out how to separate them by month seems easy enough but I can't wrap my head around how to do it by week. I'm assuming that there's some php date function that will help greatly with this but I can't find it. Hoping you all can help.
What is the best way to do this?
I haven't decided yet whether or not I'd want the weeks where there are no meetings to show the week label or not. (Ex. There are no meetings between September 10th - September 16th. - so do or do not show that label.
Link to examples (no need to sign into google)
https://docs.google.com/document/d/16cvRfPmovNBsx9QQ0U5qhVoW8bo0xjEABil3wTtEUrA/edit
Use date("W") to get the week number of the year.Then you can separate your results according to the week number.
Without knowing how your data is structured; you could use the week number returned by the date() function to keep track of which week you are in and break it up that way.
$currentWeekNumber = -1;
$rows = array(
array('id' => 5, 'started_by' => 'Ben', 'when' => '2012-09-06 09:00:00'),
array('id' => 6, 'started_by' => 'Julie', 'when' => '2012-09-07 18:00:00'),
array('id' => 18, 'started_by' => 'Ben', 'when' => '2012-09-18 20:00:00')
);
foreach($rows as $row) {
$eventSeconds = strtotime($row['when']);
$rowWeek = intval(date('W', $eventSeconds));
if( $rowWeek !== $currentWeekNumber && $currentWeekNumber !== -1) {
echo "----- Week Break ------\n";
}
$currentWeekNumber = $rowWeek;
echo "Meeting #{$row['id']}, started by {$row['started_by']}, occurs at ".strftime('%c', $eventSeconds)."\n";
}
Which produces the following output:
Meeting #5, started by Ben, occurs at Thu Sep 6 09:00:00 2012
Meeting #6, started by Julie, occurs at Fri Sep 7 18:00:00 2012
----- Week Break ------
Meeting #18, started by Ben, occurs at Tue Sep 18 20:00:00 2012

Categories