3

Let's look at those two scenarios.

First, you have a page that is using $_GET vars for routing and only requests/includes the files based on $_GET requests, like as follows:

index.php

<head>... </head>
<a href="index.php?page=home">
<a href="index.php?page=services">
...
<div id="content">
<?php
   if($_GET['page'] == "home") {
     include 'home.php';
   } elseif(...) {
     ...
   }
 ?>
 </div>

Or having index.php as follows:

<head>...</head>
<a href="home.php">
<a href="services.php">

And then loading the page separately.

Which is more maintainable and what are the possible caveats of both methods? I find that the first method comes in handy when I built already on existing framework, like Bootstrap, so I can just add piece I like and the first one is if I work with no framework at all and just build fast, dirty and cheap website.

  • I see you placed a bounty. I've updated to answer to more directly address the question as asked. – Goose Aug 4 '16 at 13:23
  • 6
    This is what we used to do a decade ago... use a framework (try Laravel). – Damien Roche Aug 4 '16 at 13:52
10

Neither really. You should have a framework for routing. That way user have URLs like example.com/home and you can use home as a variable to load different controllers. This is better than example.com/?page=home or example.com/home.php in many ways, such as code flexibility, SEO, and user experience. Since your using PHP, take a look at Fat Free Framework or CodeIgniter for some very basic frameworks that handle routing for you.

An additional note, it seems you were considering having the logic for a page all in a single file. More common and far easier once you understand it is a MVC design pattern of some sort. Here's roughly how CodeIgniter does it. Requests go to a router file, which calls a controller file with the url segments as parameters, which gets data from a Model which connects to a database if needed, and then after manipulating the data as needed uses the result to render a view file that is mostly HTML with variables echoed where needed. That's just one example of how it can be done. Look up MVC for more information on this design pattern.

If you're doing anything more than a 2 or 3 page site with never changing content that no other programmers will ever touch, it's highly recommended.

But to answer the question as asked

If you must choose one of those two methods, chances are they'll be a lot of overlap of logic between pages, at least at some point, so having one file that uses get requests to handle requests is much better than separate files. If every page needs a header, a footer, a variable, or access to some custom function, you'll be writing the code once in one place, instead of dozens of times across files. The drawbacks is you'll have a huge file with an difficult to understand and maintain mess of if statements. This is definitely still preferable to having to change every file to make any small global change.

1

Just adding on to the answer given by Goose which is pretty detailed and talks about the topic for my answer - routing.

I just want to mention that it is possible to use only routing libraries without having to use a whole MVC framework, which might be too confusing for beginners.

Maintainability means many things. But using a routing library will give you most of (if not all) the maintainability benefits you're looking for! It will be fast, clean, and you don't have to make many changes every time the navigation changes. It's also not very difficult and has a pretty flat learning curve (IMHO).

1

Setting aside all those framework advices, your suggested options have these pros&cons.

single php file

  • (+) one central point of execution; you can include common parts of app, security checks, env set up, etc... in one place and for all
  • (-) one central point of execution; you have to route traffic in one place. this may clutter up code
  • (-) basically one url for everything (sure different query parameters); this may be handicap when crawlers/indexers come to your site

separate main php files

  • (+) possibly more urls for crawlers and indexers
  • (-) you have to explicitly include common parts in every top level script

But there's another way in between these two, read on.

Maybe there is a reason you don't want to use established framework, maybe you want to learn by exploring. I don't want to judge, it's your choice.
Just you may eat the cake and have it too. Gather pros of both solution and eliminate main cons.

I propose two (and half) solutions, both are based on scenario you are using separate main .php files with their own public urls, let's say:

/index.php
/section.php
/article.php?id=123

And want to implicitly include common parts in all scripts.

rewrites

First of all, you may exploit rewrites in apache/nginx/whatever-your-httpd-is and direct all traffic to single php file. In that file you can do whatever you want to need to initialize application and than require originally requested script.

router.php:

<?php

$script = $_SERVER['SCRIPT_NAME'];
# add mandatory safety checks

require 'common.php';
require $script;

Of course, you can do a lot more in router.php or common.php, e.g. set up DB connection, autoloading, configuration options, handle prettier urls, etc...
Basically, this is what all those frameworks do for you.

prepend/append

If you are able to mangle php.ini or .htaccess files, you can set up auto_prepend_file (http://php.net/auto-prepend-file) directive for your project. And possibly auto-append-file (http://php.net/auto-append-file) too.

php.ini:

auto_prepend_file = prepend.php
auto_append_file = append.php

or .htaccess:

php_value auto_prepend_file prepend.php
php_value auto_append_file append.php

This has exactly the same effect as adding require statements on top and bottom of each top-level executed .php script (i.e. executable with public url).

This solution has added benefit of php interpreter handling execution of top level scripts, not your router. So if it's not supposed to be run from http request, .htaccess et al come do effect. You have to handle this by hand when using rewrites/router.

404 handler

This is last option, but I don't recommend it as it effectively destroys anything other than GET requests. But may be useful if you want to use both pretty urls and directly executable scripts.

Instead of rewrites, you may set up 404 handler instead. If httpd couldn't find public resource (be it static file of .php file), executes your defined handler instead. If it's an .php file, it's very similar to router.php from the rewrite solution. But I don't want to go into detail here. You better have to try and play with it yourself.

PATH_INFO

One more remark maybe useful to you.
Examine PATH_INFO environment variable (accessible as $_SERVER['PATH_INFO'] from php). And try to play with urls such as /article.php/123/pretty-name. You do not have to limit yourself to query parameters (a.k.a. $_GET). A lot of individual urls almost instantly.

0

My 2 cents on your quick and dirty methods are this: $_GET keeps the nav in one file which is easier to update than the three file in your example. On your first addition to the site, you will need to add your new nav entry to three files. On your second addition, you would then have to edit four files... Etc...

0

Here's the simple and dynamic approach for every $_GET request, no need to check if page == home or any parameters and handle error page or template if file does not exist. Also added exclusion for some files

<?php
    $file = $_GET['page'];

    $path = getcwd(); // get the current directory if the file is same as index.php
    $ext = ".php"; // file extension

    $filename = $path."/".$file.$ext; // path and file combined
    $error_page = $path."/error_page.php"; // error page template

    // this is optional if your configurations are in the same folder
    $exclude = array(
                    'db',
                    'config'
                );

    if (isset($file) || !empty($file)) { // check if page parameter is not empty or set
        if (file_exists($filename) && !in_array($file, $exclude)) { // check if file exist and if we need to exclude some config files
            echo $filename." exists"; // load template
        } else {
            echo $error_page; // load 404 template or redirect to 404 page
        }
    } else {
        echo $error_page; // load 404 template or redirect to 404 page
    }
?>
  • 4
    I believe this can be very dangerous. What if user asks for database_config.php (or fish for similar files)? In theory user can also as for ../../../some_other_file. I know it's unlikely, but it's worth to think about security and add some checking. – Volvox Aug 8 '16 at 12:08
  • Yes you're right @Volvox, it depends on how the user will include the exact path but I added option for excluding files to prevent this if the config files are in the same directory with index.php file – jQry Aug 9 '16 at 6:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.