PHP include paths

One of the nice things about PHP is that it is easy to write one common file for things like headers and footers and then include that file in every page that you publish. For simple sites, it is easy, you just include a line like this in as the first line your code.


<?php
require_once('header.inc'); ?>

where the file is something like this:

<!doctype html>
<html lang="en-US">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="copyright" content="Copyright ©<?php echo $now; ?> Well Golly.com" />
  <meta name="rating" content="general" />
  <meta name="robots" content="all" />
  <meta name="description" lang="en" content="<?php echo $meta_description; ?>"/>
  <meta name="keywords" content="<?php echo $meta_keywords; ?>" />
  <meta name="robots" lang="en" content="index follow" />

    <link rel="icon" type="image/png" href="./common_images/favicon.png" />
    <link rel="apple-touch-icon" href="./common_images/apple-touch-icon.png"/>
    <link rel="stylesheet" href="/css/pure-min.css">
    <title><?php echo $page_title; ?></title>
</head>

Once you have the basic file in place, you can start embellishing it. Note that I refer to several PHP variables. If you examine the source for this page, you see that it is copied literally into the HTML source and a few variables that I previously defined take on their values. These are defined in a file that I call set_variables.inc.


<?php
    $day = date("Y-m-d",strtotime("now"));
    $today = date("Y-m-d");
    $nowDate = date('Y');    // Used for copyright notices in the header tag and in the footer.

  // Here is where you provide information about your site.
  $site_name = "Well Golly";
  $site_shortName = "Well Golly";
  $site_URL = "https://Well Golly.com";

  $copyright_text = "© Copyright $nowDate $site_name";
  $footer_text = "&copy; Copyright $nowDate <a href=\"{$site_URL}\">$site_name</a> $site_address&nbsp;&nbsp;$site_phone";

  $keywords = "$site_name"; // Separate terms with commas
  $description = "$site_name web-based exercises.";

  $meta_description = 'Well Golly Exercises.';
    $meta_keywords = 'products, apps, software';

  $page_title = "$site_name Exercises";

?>

Note that this file starts with because none of the information on the page is HTML. This file defines variables that I use in other files to generate HTML.

One thing that is confusing at first is how PHP finds the included files. If you just use the file name in the call, then PHP looks in the current directory for the file. PHP uses Unix conventions, so if you are in a subdirectory and want to call a file one level above, you would preface the file name with ../ e.g.


<?php
require_once('../header.inc'); ?>

Likewise, two levels up is ../../ and two levels up then down a level is ../../directory. This can get confusing after a while so what most people do is create a directory in the document root and put include files that are used throughout the site in it. Here’s an example of my include.php file for a site.


agreement.inc
check_login.inc
footer_menu.inc
footer.inc
header_logo.inc
header_menu.inc
header.inc
login_validation.inc
set_variables.inc
signup_confirmation.inc
signup_form.inc
signup_updateDB.inc
signup_validation.inc
timeZones.inc

Remembering to put the correct number of ../s can be tiresome so what I do is define a search path and put it in my php.ini file. I don’t remember precisely what it looks like, but this line from my /var/log/php_error.log file tells me where PHP was looking for a file that it can’t find.


 PHP Fatal error:  require_once(): Failed opening required './include.php/header_menu.inc' (include_path='.:/usr/share/php5:/usr/share/php:./include.php:..:../include.php:../../include.php:../../../include.php')

I basically says to look first in the current directory . , then in the PHP provided directories, then in the next level up, etc. If you want to override the search path you can just specify where PHP should look for the file. For example, in the page where users interact with your app, you may not want all of the normal branding and menu choices. Create a simple header file and access it directly by specifying the path.

<?php
require_once('./header.inc'); ?>

You can do the same thing for CSS and javascript. I do this for all of my apps since there is some common javascript but much of it is specific to an app and I don”t want the code to get confused because I used a function name that has a different input and output in other apps. Plus there is less code being downloaded so the page loads faster.

Where it gets tricky is when you start thinking that PHP starts looking in the document root for files and images when in fact it starts looking in the root of the server as defined in your Apache2 conf file. In my case it is /srv/www.

So if you want to include an image in your logo, you might put it in /common_images in the document root. However, if you call it using <img src='/common_images/logo.png' alt=logo' /> PHP won’t find it because it will be looking in /srv/www//common_images/logo.png. Remove the first slash and you are good to go—if you are calling the images from the same level as common_images. You could add the path to your php.ini file, but I have a bunch of folders that I use where I would have to do that. An easier way is to use PHP server variables. In the example below, I have already defined the $site_URL in my set_varialbles.inc file and use a built-in PHP function, explode, to get the filename of the directory where my common_images directory is located. So no matter how far down the directory tree I am, I can still get the location where the logo is located—https://beta.wellgolly.com/exercises/common_images.


<div id="header" class="pure-g">
  <div class="pure-u-1 pure-u-lg-1-2">
    <a href="<?php echo $site_URL ?>">
    <?php 
      $curRoot = explode("/", $_SERVER['REQUEST_URI']);
    ?>
      <img class="pure-img-responsive" src="<?php echo "{$site_URL}/{$curRoot[1]}" ?>/common_images/wg_header.png" alt="Header">
    </a>
  </div>
</div>

Finding paths with PHP

I’m worling on web apps and need to do two things that require knowing where you are in the file hierarchy. When a user clicks on an app that I am charging for, I need them to log in. But when they are done with the login, I want to send them back to the app that they want to use. So what I do is use the server variable PHP_SELF to get the complete URL of the file they clicked on. I need to make sure that there is a active session and then add a session variable, calledFileName. Once the user has finished the login or signup process, I redirect them to the app they want to use.


// if user is not logged in, restrict what they can do
$calledFileName = $_SERVER['PHP_SELF'];
session_start();
$_SESSION['calledFileName'] = $calledFileName;

When they hit the submit button, I call a bunch of validation code and reload the form page. Before any HTML is sent, I check to see how they got to the login/signup page and then send them to the appropriate page.


$startlocation = $_SESSION['calledFileName'];
if ($passwordIsValid) {
  if ( strlen($startlocation) > 0 ) {
    header("Location: $startlocation");
  } else {
    header("Location: /exercises/overview.php");
  }
}

Most of my web pages have been fairly simple so I the past I have done live editing to fix mistakes or update text. When I converted one of my sites to responsive HTML5, I created a beta subdomain, e.g. beta.wellgolly.com, and did all the changes there and them rsynced the whole thing to the original site. That worked because I used hard coded paths and one global variable for the site domain name.

I have active users of the exercises and I don’t want to break things for them so live editing is out. I am developing on a beta subdomain, but I want to be extra careful that nothing breaks. I also want to make the site robust enough that I can easily move it to another domain if someone wants to license the apps. So rather than absolute paths, I’ve been using relative paths. This mostly works, but there are some instances where I want to use the same file in different locations and the images that file calls need a fixed path.

I have been using git to sync the files and it seems to work as well as rsync. Because I want to be extra careful about breaking the site for active users, I created a test folder for the exercises on the live site, exercises_test, and synched it with the beta content. Then renamed it when I was sure everything was working. The relative paths work fine but hard coded paths won’t work in this case since the files are not located in /exercises/folder but are located in /exercises_test/folder. One case where it doesn’t work is when I redirect the user to the login page if they haven’t yet logged in. In this case, I use another server variable and grab the root directory. The variable looks like this: /exercises_test/apptype/index.php so when I grab the root folder with explode, the first element of the array is empty, so I need to get the second element of the array.


if ($_SESSION['userID'] == '') {
  header("HTTP/1.1 302 Found");
  $curRoot = explode("/", $_SERVER['REQUEST_URI']);
    header("Location: /$curRoot[1]/login.php");
    die();
}

I can use this same trick for path names in my header files.

PHP password storage in MariaDB

Years ago I built a site that had login and account creation capability using SHA1 and MySQL. In preparation for a new webiste I loaded the old site into a droplet it still works fine. At the time SHA1 and simple input sanitizing was fine, but since then SHA1 has been cracked and PDO is recommended for sanitizing database values.

The original code looked like this:


// Read the data from the form
$userlogin = htmlspecialchars($_POST['login']);
$password  = htmlspecialchars($_POST['password'];
// The hash stored in the database.
$passwdHash = sha1($Password);

// Verification
$userlogin = htmlspecialchars($_POST['login']);
$password  = htmlspecialchars$_POST['password'];
$passwdHash = sha1($password);
$sql = "SELECT *
FROM users
WHERE username = '$login' && password = '$passwdHash' ";

Without really thinking about it, I sanitized the password input with htmlspecialchars and in both storing and retrieving the password it didn’t have any impact.

I basically copied the code into my new project and then changed SHA1 to password_hash. That didn’t work because the password_hash requires password_verify to check the hash when you retrieve it from the database. That worked when I tested the login code by copying and pasting the login info from php_error.log –> error_log(login: $userlogin  hash: $hash) into the users table. It didn’t work when I created a signup page and entered the data automatically. The reason is that sanitizing the password with htmlspecialchars changes it somehow. This is what I do instead. Note that it doesn’t matter what the user enters in the password field because the hash function transforms it into a 60 character hash so there is no need to sanitize.


// Read the data from the form
// Sanitized passord is used in javascript just for checking that a password was entered
$Password = htmlspecialchars($_POST["Password"]); 
$UserLogin = htmlspecialchars($_POST["UserLogin"]);
$PasswdHash = password_hash($_POST["Password"], PASSWORD_DEFAULT);

// Enter into the database with PDO
$sql = "INSERT INTO `Database`.`users` (`user_login`, `user_pass`,
$sql .=  "VALUES (:user_login, user_pass, ...

$stmt->bindParam(': user_login', $UserLogin);
$stmt->bindParam(':user_pass',   $PasswdHash);
...

// Validate the password. Retrieve by user_login only. 
// Don’t do anything to the password that was entered by the user.

foreach($result as $row) {
  $user_login  = $row['user_login'];
  $hash = $row['user_pass'];

  if ( password_verify($_POST['password'], $hash) ) {
    $_SESSION['userID']    = $row['ID'];
    $_SESSION['userName']   = $row['user_name'];
    $_SESSION['userDisplayName'] = $row['display_name'];
    $passwordIsValid = TRUE;
  }

Randomizing a PHP Array

I wrote this before it occurred to me to see if MariaDB could randomize the output. It can, with ORDER BY RAND();.

PHP has a shuffle function that can randomize one array, but I have a bunch that need to have the same random order.


// Create an array of numbers
$randomArray = range(0,$numWords-1); 
shuffle($randomArray); 

// Create empty target arrays     
$word = []; $sounds = []; $phrase = []; $sentence = [];

for ( $i = 0; $i < $numWords; $i++ ) {
  // Use the numbers in the random array to swap elements.
  $random = $randomArray[$i];
  $word[$i] = $word_S[$random];
  $sounds[$i] = $sounds_S[$random];
  $phrase[$i] = $phrase_S[$random];
  $sentence[$i] = $sentence_S[$random];
}

Write to a file from PHP

I probably covered this before, but I want to keep some log files of what is happening on various pages on a site. I could write to the php error log, but I look at those every morning and then erase them. I want something that sticks around but I don’t need a whole lot.

This solution works for me.


 $fname = "./interesting_stuff.log";
 $info = "Message";
 
 $fp = fopen($fname, 'w');
 fwrite ($fp, "$info" . "\r");
 fclose($fp);

You’ll need to create the file and set the permissions so everyone can write to it before it will work.