1
\$\begingroup\$

I am new to HTML and programming in general and am currently working on setting up my first website.

For this I created a couple of PHP pages with a separate file for each of them and in order to avoid duplicating code I tried to remove as much as possible from the pages header and saved this in a separate header file. The header file (header.php) is then included on all pages through the following which is the first part of code on each page file:

<!-- header -->
<?php 
    require_once("includes/header.php"); 
?>

Now so far all my pages are working but I am not sure if the structure of my header is ideal and if there is anything I should add or change there - especially regarding the part where I include PHP as I heard that there can be issues with the structure when trying to set up a session etc.

Would be great if someone could have a look at this and let me know your feedback or suggestions.

My complete header file:

<!DOCTYPE html>
<html>
    <head>
        <?php 
            define("someUnguessableVariable", "anotherUnguessableVariable");
            session_start();
            if(!isset($_SESSION["login"]) && $_SESSION["login"] == ""){
                header("location: login.php");
                exit;
            }

            include "system/config.php";

            $pageURL = basename($_SERVER["REQUEST_URI"]);
            $pageName = pathinfo(parse_url($pageURL, PHP_URL_PATH), PATHINFO_FILENAME); 

            $selectedLang = $_GET["lang"];
                if(!isset($selectedLang)){
                    $selectedLang = "de";
                }
            $langURL = "?lang=" . $selectedLang;

            $conn = new mysqli($dbServer, $dbUser, $dbPass, $dbName);
            $conn->set_charset("utf8");
            if($conn->connect_error){
                die("Connection failed: " . $conn->connect_error);
            } 
            // fetch main translations
            $location = "%main%";
            $stmt = $conn->prepare("SELECT tID, " . $selectedLang . " FROM TranslationsMain WHERE location LIKE ? ORDER BY tID");
            $stmt->bind_param("s", $location);
            $stmt->execute();
            $result = $stmt->get_result();  
            while($arrTranslations = $result->fetch_assoc()){
                $trans[] = array("ID" => $arrTranslations["tID"], "trans" => $arrTranslations[$selectedLang]);
            }
            $conn->close();

            // get main translations by ID
            function fetchTransMain($trans, $itemID){
                foreach($trans as $key => $val){
                    if($val["ID"] == $itemID){
                        return $val["trans"];
                    }
                }
            }
        ?>

        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta name="author" content="Some author" />
        <meta name="description" content="Created: 2015-06" />

        <base href="http://www.myurl.de" target="_self" />

        <title>Some title</title>

        <!-- CSS -->        
        <link rel="stylesheet" type="text/css" href="includes/styles.css" />
        <!-- CSS - Font Awesome -->
        <link rel="stylesheet" type="text/css" href="http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" />

        <!-- favicon -->
        <link rel="shortcut icon" href="images/favicon/favicon.ico" type="image/x-icon" />
        <link rel="icon" href="images/favicon/favicon.png" type="image/png" />
        <link rel="icon" sizes="32x32" href="images/favicon/favicon-32.png" type="image/png" />
        <link rel="icon" sizes="64x64" href="images/favicon/favicon-64.png" type="image/png" />
        <link rel="icon" sizes="96x96" href="images/favicon/favicon-96.png" type="image/png" />
        <link rel="icon" sizes="196x196" href="images/favicon/favicon-196.png" type="image/png" />
        <link rel="apple-touch-icon" sizes="152x152" href="images/favicon/apple-touch-icon.png" />
        <link rel="apple-touch-icon" sizes="60x60" href="images/favicon/apple-touch-icon-60x60.png" />
        <link rel="apple-touch-icon" sizes="76x76" href="images/favicon/apple-touch-icon-76x76.png" />
        <link rel="apple-touch-icon" sizes="114x114" href="images/favicon/apple-touch-icon-114x114.png" />
        <link rel="apple-touch-icon" sizes="120x120" href="images/favicon/apple-touch-icon-120x120.png" />
        <link rel="apple-touch-icon" sizes="144x144" href="images/favicon/apple-touch-icon-144x144.png" />
        <meta name="msapplication-TileImage" content="favicon-144.png" />
        <meta name="msapplication-TileColor" content="#ffffff" />

        <script>
            var baseURL = '<?php echo $baseURL; ?>';
            var pageURL = '<?php echo $pageURL; ?>';
            var pageName = '<?php echo $pageName; ?>';
            var selectedLang = '<?php echo $selectedLang; ?>';
        </script>
    </head>   
    <body>

Note: jQuery and JavaScript are included separately through a footer file to improve loading of the pages.

\$\endgroup\$
2
\$\begingroup\$

It's usually better to define the front-end code (HTML) separately to the back-end/database connections, as it allows a clean separation of your app's logic (controllers) from the content that's served to users. I'd suggest restructuring the top of your app as follows:

<?php
    include 'inc/main.php';
?>
<!DOCTYPE html>
<html>
<?= html_head(); ?>

Some main reasons being:

  1. You don't want to repeat the same database connection logic for pages that use other templates.
    An obvious example of this would be AJAX requests being made to another page. Having the database connection declared in a function specific to displaying an opening block of HTML code means you'd have to repeat the DB connection in another file (never forget the DRY principle), or use a config file to store the host's credentials - which adds needless fracturing. A better approach would be to include the database connection in inc/main.php (which we can think of as your app's bootstrap or primary controller).

  2. You can serve arguments to a function, but not to an included file.
    WordPress is probably the best-known example of how well this pattern plays out. Each of the primary front-end components of a page's anatomy is generated using a "template tag", which accepts optional parameters and filters. Passing parameters to a function to adjust its behaviour is a lot more explicit than, say, declaring globals early on and having them read inside another file. Compare doing this:

<?php
    # Load whatever properties you need to populate the page's content
    $page_params = array(...);
?>
<!DOCTYPE html>
<html>

<?php
   html_header(array(
       'title' => $page_params['page_title'],
       'extra_stylesheets' => $page_params['stylesheets'],
       'og_data' => $para_params['og_data']
    ));
?>

... with this:

<?php
    $title = 'My cool title';
?>
<!DOCTYPE html>
<html>

<?php
    include 'inc/page_header.php';
?>

Where it's completely unapparent to anybody else reading this that inc/page_header.php is reliant on the $title global without checking the file itself:

<?php
   # inc/page_header.php
   global $title;

   ?>
   
   <?php
?>

Of course, this says nothing about the issue of global naming conflicts, either (two variables with the same name might clash, overwriting each other with odd results).

When your webapp starts getting bigger, you'll inevitably find your list of globals increasing, and that's when things can start getting hairy. Restricting what needs to be customised to parameters served to dedicated functions can prevent your code from becoming spaghetti.

  1. Your server should've finished configuring everything by the time the first byte of HTML is sent. Initiating sessions, authenticating users, checking for redirects... these are all things that should ideally be done in the app's main bootstrap (which I listed in the previous example as inc/main.php). Load libraries of helper functions, set whatever globals or constants you need to, then start preparing a response.

I hope this has been of help for you. :) Good luck.

\$\endgroup\$
  • \$\begingroup\$ Ok, this is really great and helps a lot ! However, I am not sure about a few parts, probably since this is all new to me, so just to confirm regarding the following chunks: I would put the first code you posted on top of each of my page files and would then split my current header onto two separate include files, one only containing the remaining HTML and one for the rest, is that correct ? How and where would I handle the session start and check then ? \$\endgroup\$ – keewee279 Jun 25 '15 at 13:30
  • \$\begingroup\$ The session checking should be taken care of inside inc/main.php (or whatever you've chosen to name it). But what exactly is the session being used for, if I'm allowed to ask? \$\endgroup\$ – user76420 Jun 25 '15 at 13:48
  • \$\begingroup\$ Sure, thanks. I would like to use the session to check if a user is already logged in and otherwise redirect them to a login page (login.php). Does that make sense ? Please let me know if I am missing something important there. :) \$\endgroup\$ – keewee279 Jun 25 '15 at 13:50
  • 1
    \$\begingroup\$ Yes, it does. However, you'll be unable to redirect them anywhere if the first byte of content has already been sent. Which is another reason you'll want to include all the main backend logic before outputting any content. \$\endgroup\$ – user76420 Jun 25 '15 at 13:53
  • 1
    \$\begingroup\$ More or less. Generally, the average webapp page will be HTML broken up with segments of PHP logic that's used elsewhere. For example, listing a table of users would involve a database query and displaying the collected results, both of which can be contained inside an embedded PHP block within the HTML body tag itself. Try to avoid wrapping your logic up in a function if it's only used on one page; use functions once you find yourself repeating some logic (the table of users, for example, might later be used for a table of competition entries or whatever...) \$\endgroup\$ – user76420 Jun 25 '15 at 14:08

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.