5

I have this script:

<?php
if(urldecode($_SERVER['REQUEST_URI']) == "/?articles")
{
    include("Articles.php");
}
?>

Which allows me to setup a custom URL for a page. Now, the problem occurs comes when I need URLs like these:

/?articles | Page that contains newest articles which loads when user clicks "< Previous" button
/?articles&1 | Page that contains older articles which loads when user clicks "Next >" button
/?articles&2 | Page that contains older than older articles
/?articles&3 | Page that contains old articles
/?articles&4 | Page that contains old articles
/?articles&5 | Page that contains oldest articles
/?articles&6 | Page that contains oldest articles, also last page in the pagination

And so on. Namely, the code in the script above would be like this:

if(urldecode($_SERVER['REQUEST_URI']) == "/?articles&1")
{
    include("Articles-500.php");
}
if(urldecode($_SERVER['REQUEST_URI']) == "/?articles&2")
{
    include("Articles-499.php");
}
if(urldecode($_SERVER['REQUEST_URI']) == "/?articles&3")
{
    include("Articles-498.php");
}
if(urldecode($_SERVER['REQUEST_URI']) == "/?articles&4")
{
    include("Articles-497.php");
}
if(urldecode($_SERVER['REQUEST_URI']) == "/?articles&5")
{
    include("Articles-496.php");
}
if(urldecode($_SERVER['REQUEST_URI']) == "/?articles&6")
{
    include("Articles-495.php");
}

But each time the page with the newest articles gets filled (contains 10 articles per page) I have to update the script like this:

if(urldecode($_SERVER['REQUEST_URI']) == "/?articles&1")
{
    include("Articles-505.php");
}
if(urldecode($_SERVER['REQUEST_URI']) == "/?articles&1")
{
    include("Articles-504.php");
}
if(urldecode($_SERVER['REQUEST_URI']) == "/?articles&1")
{
    include("Articles-503.php");
}
if(urldecode($_SERVER['REQUEST_URI']) == "/?articles&1")
{
    include("Articles-501.php");
}
if(urldecode($_SERVER['REQUEST_URI']) == "/?articles&1")
{
    include("Articles-500.php");
}

I also need you to tell me how to use it practically in my navigation, id est: <A href="?">Next</A> and <A href="?">Previous</A>

  • There is something unclear for me, the first one `/?articles |...` in your problems list. It should not be a problem because it is true with your `if` in the first code snippet. – SaidbakR May 18 '20 at 23:50
  • Each page has its own custom URL in this PHP script. The `/?articles` is the default page, every other is paginated. –  May 18 '20 at 23:55
  • 2
    That's not really how you do pagination. You shouldn't use redirects. You should read the query parameter in your articles.php and show data according to what was received. See https://www.php.net/manual/en/reserved.variables.get.php and for an example see https://www.allphptricks.com/create-simple-pagination-using-php-and-mysqli/ – brunorey May 19 '20 at 02:21
  • This is not an actual answer to my problem, is it? I do not need MySQL, I need it to be done purely through this script, if possible. –  May 19 '20 at 11:04
  • It's not a direct answer to your question, no. I was trying to give you a sense of how pagination is usually done. I do not recommend you to follow the path you are currently going for, that's why I didn't post an answer. I do recommend you visit those links and try to understand how pagination is done and review your strategy. They won't work just to copy-paste them into your solution (e.g. without using mysql). Seriously, me advise: don't use redirects, do use GET parameter parsing. – brunorey May 19 '20 at 14:04
  • I guess no one really bothers to give me a solution to this. Instead, I get redirects and other recommendations. I know about different (and more "proper") ways of pagination: if I wanted them, I would have Googled them myself instead of asking a question/for help here... But nobody really listens these days anymore, nor gives effort to actually help with what is actually asked for. As I wrote earlier, I need pagination built in my script above. I do not need/want MySQL with this particular issue. I used GET before I switched to this script now. I thank you for your attention and try to help. –  May 19 '20 at 16:27
  • Why do you need to have such a lot of files to be included? Why not generate them dynamically, based on the pagination? – Nico Haase May 28 '20 at 06:25
  • I guess the content of the articles are hardcoded in the php page, hence why the OP is stating he understands but cannot apply a paging done with the help of a DB? Just my own guess though. – β.εηοιτ.βε May 28 '20 at 07:40
  • 1
    Is there any reason you not using regular `$_GET` parameters like `?action=articles&page=5`? Then you could just use `if ('articles' === $_GET['action'])` and `$page = $_GET['page'] ?? 'newest'` – qooplmao Jun 21 '20 at 01:46

5 Answers5

4

What you can do, in order to have this created dynamically is to use the function glob that can list you all the files in a directory.

So given that you would have the files:

  • Articles-1.php
  • Articles-2.php
  • Articles-3.php
  • ...

Now, if your articles are indeed named as above (Articles-1.php and not Articles-001.php) you will face the problem that a simple alphabetical sort won't work.
Indeed, Articles-99.php will always show up earlier than Articles-505.php in a simple alphabetical sort.

But, hopefully, PHP offers us the really neat sorting which is natsort().

This function implements a sort algorithm that orders alphanumeric strings in the way a human being would while maintaining key/value associations. This is described as a "natural ordering". An example of the difference between this algorithm and the regular computer string sorting algorithms (used in sort()) can be seen in the example below.

Sorting via natsort() is nicer than my original usort idea, all credit for this idea goes to dılo sürücü's answer.

Still, we need the sorting to be in a reverse order, and this can be provided using the SORT_NATURAL flag on rsort().

SORT_NATURAL - compare items as strings using "natural ordering" like natsort()

Source: https://www.php.net/manual/en/function.sort.php
Credit for the usage of this flag goes to Seh Horng's answer

// Listing all the articles pages
$articles = glob("Articles-*.php");
// Applying reverse natural sorting, with SORT_NATURAL flag on rsort
rsort($articles, SORT_NATURAL);

/**
 * Extracting the selected page out of the REQUEST_URI, 
 * and transform it an integer
 */
$selectedPage = intval(
  str_replace("/?articles&", "", urldecode($_SERVER['REQUEST_URI']))
);

/**
 * This is a sanity check; 
 * just in case someone tries to access a page that does not exists,
 * like the page 99999999999
 * It also tackles the case when intval fails and returns 0
 * causing the index to be 0 - 1 = -1
 *
 * By the way, doing this check also covers your default behaviour
 * on the URL /?articles
 */
if(array_key_exists($selectedPage - 1, $articles)){

  /** 
   * We need to remove one from the selected page, 
   * remembering an array start at 0 in PHP
   */
  include $articles[$selectedPage - 1];
} else {
  include "Articles.php";
}

This should give you the right include dynamically.

β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83
  • My apology, I forgot about this problem I posted since I did not get any answer earlier. Anyhow, considering I have this script, what U. R. L. should I add to my ? Also I need to add this code to my original script above, right? –  Jun 10 '20 at 12:45
  • By adding this to my code, all clicking on the site is disabled. –  Jun 14 '20 at 20:12
  • I am not concerned, and your choice of giving the accepted answer is yours, believe me, I get that. I just do not see any link in your original question, so I don't get the follow up question. – β.εηοιτ.βε Jun 14 '20 at 21:50
  • Also the navigation with this should be something generic, like `/?articles&forward` and `/?articles&backward`. If I add `/?articles&1` and `/?articles&2` to navigation links to each page, is not going to help me much. And you did not exactly instruct me on what to add to `` in order to move between pages, you just gave me the code but not how to use it. –  Jun 14 '20 at 21:52
  • You do realise that this is not part of your question, do you? Maybe you should edit it, if you want an answer to this part also? – β.εηοιτ.βε Jun 15 '20 at 09:29
  • Okay, if you say so, I did it. –  Jun 15 '20 at 14:31
2

Assuming that there will always be only 6 articles. You can try the following script:

<?php

//get array of php files in the current folder matching Articles-*.php
$phpfiles = glob("Articles\-*.php");

//sort by descending order
$sorted = rsort($phpfiles, SORT_NATURAL);

//use only the first 6 php files in the sorted array list
if(urldecode($_SERVER['REQUEST_URI']) == "/?articles&1")
{
    include($sorted[0]);
}
if(urldecode($_SERVER['REQUEST_URI']) == "/?articles&2")
{
    include($sorted[1]);
}
if(urldecode($_SERVER['REQUEST_URI']) == "/?articles&3")
{
    include($sorted[2]);
}
if(urldecode($_SERVER['REQUEST_URI']) == "/?articles&4")
{
    include($sorted[3]);
}
if(urldecode($_SERVER['REQUEST_URI']) == "/?articles&5")
{
    include($sorted[4]);
}
if(urldecode($_SERVER['REQUEST_URI']) == "/?articles&6")
{
    include($sorted[5]);
}

?>
Seh Horng
  • 41
  • 1
  • 4
  • 1
    ...as an addition: `glob` will return a **sorted** array, so maybe you could simply use it in descending order instead of re-sorting it? – Nico Haase May 28 '20 at 06:26
  • `rsort` or the original sort of `glob`, as pointed by @NicoHaase won't work because normal sorting will always brind `something-99` above `something-888888888`. The `natsort` idea though, is the good one. – β.εηοιτ.βε May 28 '20 at 07:36
  • 1
    good point. rsort do have natural ordering option. I have updated the answer to take natural ordering into account. – Seh Horng May 28 '20 at 07:44
2
$articles=glob('Article-*.php');
$sortedArticles=natsort($articles); 

$articleIndex=$_GET['articles'] ?? null;

$article=$sortedArticles[$articleIndex] ?? "Article.php";

include_once (string)$article;
dılo sürücü
  • 3,821
  • 1
  • 26
  • 28
  • 1
    Please add some explanation to your answer such that others can lean from it – Nico Haase May 28 '20 at 06:24
  • 1
    Thumbs up for the `natsort()` idea, although you should really add some explanation as pointed by @NicoHaase. Sadly your `$_GET` won't work on OP requirement, though, as the URL is `?/?articles&1` and not `/?articles=1`. – β.εηοιτ.βε May 28 '20 at 07:34
  • Mhm, `natsort` keeps the key/value association, though, so there is still something missing here – β.εηοιτ.βε May 28 '20 at 07:47
  • What parameters I need to add to pagination links in order for this script to work? Each page with articles needs to have for navigation purpose. –  Jun 10 '20 at 12:48
2
<?php 

/*Supposing this our url :  path/?articles&3   
  and we have in serveur this articles 
  articles-498.php
  articles-500.php
  articles-499.php
  articles-496.php
  articles-497.php
  articles-495.php
*/
$current_url = parse_url($_SERVER['REQUEST_URI']); 
$path        = $current_url["path"]; //return articles&3

preg_match_all('!\d+!', $current_url["query"], $matches); //get the number of article
$index = current($matches)[0]; // now we have the index is 3
 
$articles = glob("articles-*.php"); // for get all the article 
rsort($articles, SORT_NATURAL);  // sort the article to get the new article 500-499-498 ...


$pages=array();
for($i=0;$i<count($articles);$i++){
     $x = $i+1;
     $pages["articles&".$x]=$articles[$i];
}
 // This array will return like this print_r($pages);
 /*
Array
(
    [articles&1] => articles-500.php
    [articles&2] => articles-499.php
    [articles&3] => articles-498.php
    [articles&4] => articles-497.php
    [articles&5] => articles-496.php
    [articles&6] => articles-495.php 
 
 */

/* here we check if the artile is exist in our serveur*/
if(file_exists($pages["articles&".$index])){
    //if exists
$current  = array_search($pages["articles&".$index], $pages);  // get the current article  articles&3
$Next     = array_search($pages["articles&".intval($index+1)], $pages); // this is next article  3+1  [articles&4] => articles-497.php
$Previous = array_search($pages["articles&".intval($index-1)], $pages); // this is Previous article  3-1  [articles&2] => articles-499.php

//include the current article 
include($pages["articles&".$index]);
  
  // and then show your tag a like this 
  echo "<br><a href='$path?".$Previous."'>Previous</a> Current Page : 
    ".$current." <a href='$path?".$Next."'>Next</a>";

}elseif($current_url["query"] == "articles"){
  include("articles.php");
  echo "<br><a href='$path?articles&1'>Next</a>";
 }else{
  echo "Page Not Found <a href='$path?articles'>Back to articles</a> !!";
 }


// final reuslt is 
/*

content of articles&3 

<a href='path/?articles&2'>Previous</a> Current Page : articles&3 <a href='path/?articles&4'>Next</a>

*/

die;

?>

Version Online DEMO CHECK HERE

Younes Zaidi
  • 1,180
  • 1
  • 8
  • 25
1

Why not use $_GET global? If you already use parameters in URL then php should put them inside $_GET, you just have to assign values to them.

With URL like this:

/?articles=1

You will have seted $_GET['articles'] which you can check if exist and if it does just include Article.

if(isset($_GET['articles'])) {
  include("Articles.php");
}

And this method will also help you with pagination because you will have actual value in $_GET['articles'] so you could just do something like this:

<a href="?articles=<?= $_GET['articles'] + 1 ?>">Next</a> 

and

<a href="?articles=<?= $_GET['articles'] - 1 ?>">Previous</a>

and you will have to create if for checking when to hide previous or next button accordingly based on value of $_GET['articles'] (if it's equal to 1 then hide previous if equal to 6 hide next)

Or if you want to separate pagination and page action then you could just use two parameters:

/?page=articles&pagination=1

For your problem with including articles I would use DirectoryIterator which will allow you to iterate over all files in given folder and choose 6 newest files by using filectime() which return timestamp of when file was created and getting first 6 biggest values.

For example (created with this answer):

$dir = new DirectoryIterator(__DIR__);

  $articles = [];

  foreach ($dir as $file) {
    if ($file->isDot()) continue; // here we check if it's not a hidden file

    $articles[] = array(
      "path"  => $file->getPathname(),
      "cTime" => filectime($file->getPathname())
    );
  }

  $columns = array_column($articles, 'cTime');

  array_multisort($columns, SORT_DESC, $articles);

  print_r($articles);

Which will return all files in the directory in which script is placed, sorted by time they were created by newest (Descending).

This method is especially good because you don't depend on names and enumeration but on time the files were created. You can change it to time when they were modified so the updated posts will be newest.

NOTES

I'm pretty sure you know this but to have to sanitize data if you are giving user access and possibility to change it. I'm taking about $_GET from which I recommend getting values. Here is good answer on how to.

I also recommend to check if value is in proper format, for example pagination- it must be always an positive integer and lower or equal then 6:

if (isset($_GET['pagination']) && filter_var($_GET['pagination'], FILTER_VALIDATE_INT) !== false && $_GET['pagination'] > 0 &&  $_GET['pagination'] <= 6) {
   // code here
}
Mortimer
  • 300
  • 5
  • 11