Software, your way.
burger menu icon
WillMaster

WillMaster > LibraryWeb Page and Site Features

FREE! Coding tips, tricks, and treasures.

Possibilities weekly ezine

Get the weekly email website developers read:

 

Your email address

name@example.com
YES! Send Possibilities every week!

Ultra-Simple Membership

When you need a way to quickly implement an easy-to-maintain membership functionality for your website, Ultra-Simple Membership may be exactly what you are looking for.

This is not sophisticated software with a myriad of options. It is a simple thing.

It is intended for use when you want to let some people see certain web pages, perhaps your family or your customers. You manually add them to the member roster. They log in with their username and password. (Their username may be their email address.)

To install Ultra-Simple Membership, upload two PHP scripts. One of the scripts is the dashboard and the other is the membership page monitor.

To use Ultra-Simple Membership:

  1. Log into your dashboard and provide:

    • The cookie name for the membership and how long the cookie shall last.

    • A list of usernames and passwords for member accounts.

  2. Insert a line of PHP code into every web page that is to be exclusively a member page.

When someone tries to load a member page and they are not logged in, they will see a log-in form instead of the member page. When logged in, the page comes up.

Use your dashboard to add and remove members. Also, if needed, to change the log-in cookie name and/or how long the cookie shall last.

With the line of PHP code to block non-members, member pages can't be seen unless the member cookie is present in the browser.

Installing the Membership Software

There are two PHP scripts. Each has a bit of customization.

  1. The dashboard script has 3 places to customize — data file location, dashboard username, dashboard password. The file may have any legitimate *.php file name. In this article, USM_dashboard.php is assumed to be its file name.

  2. The page monitor script has 1 place to customize — data file location. As is the case for the dashboard script, this file may have any legitimate *.php file name. Here, USM_monitor.php is assumed to be its file name.

The dashboard looks something like this (screenshot may be resized to display in your device).

Determine where on your domain server the scripts will be uploaded to. They will both be uploaded to the same directory. (Make a note of this directory as the data file location may rely on it.)

Because both PHP scripts need to be customized with the data file location, the location should be decided first.

Generally, the data file would be a subdomain of where the scripts are installed, but it can be anywhere. In this article, subdomain USMdata with location USMdata/USM.txt is assumed for the file location.

If the data file location is a subdomain of the PHP scripts, it can be specified as indicated in the previous paragraph. Otherwise, specify the location as relative to the document root directory. Example: /subdirectory/USMdata/USM.txt

USM_monitor.php

Let's customize USM_monitor.php first because it has only one place to customize — to specify the data file location. Here is the PHP script source code.

<?php
/*
Ultra-Simple Membership
Monitor Unit
Version 1.0
November 24, 2019
Will Bontrager Software LLC
https://www.willmaster.com/
*/

/* *** Customizations *** */
// One place to customize.

// Specify the location of the membership data file. 
//    This must be identical to the location specified 
//    in the USM_dashboard.php dashboard file.
// Specify the file's server location, not its URL.
// The directory and file must be writable by PHP.

$MemberDataFile = "USMdata/USM.txt";

/* *** Customization End *** */

mb_regex_encoding('UTF-8');
mb_internal_encoding('UTF-8');
ini_set('display_errors',1);
error_reporting(E_ALL);
if( ! ini_get('date.timezone') ) { date_default_timezone_set('UTC'); }
$MemberDataFile = trim($MemberDataFile);
if( strpos($MemberDataFile,'/')===0 )
{
   $MemberDataFile = preg_replace( '/^'.preg_quote($_SERVER['DOCUMENT_ROOT'],'/').'/', $_SERVER['DOCUMENT_ROOT'], $MemberDataFile );
   $MemberDataFile = "{$_SERVER['DOCUMENT_ROOT']}$MemberDataFile";
   $MemberDataFile = preg_replace('!//+!','/',$MemberDataFile);
}
$Members = @file($MemberDataFile);
if( count($Members) < 2 )
{
   echo '<p>Blank data file or unable to find members in it.</p>';
   exit;
}
$Expire = false;
$CookieName = trim(array_shift($Members));
if( preg_match('/\s/',$CookieName) ) { list($CookieName,$Expire) = preg_split('/\s/',$CookieName,2); }
if( empty($_COOKIE[$CookieName]) )
{
   if( isset($_POST['un']) and strlen($_POST['un'])>0 and $_POST['pw'] and strlen($_POST['pw'])>0 )
   {
      $un = strtolower($_POST['un']);
      $sha1pw = sha1(trim($_POST['pw']));
      $isOK = false;
      foreach( $Members as $line )
      {
         list($u,$p) = explode("\t",$line,2);
         $u = strtolower($u);
         $p = trim($p);
         if( $un == $u and $sha1pw == $p )
         {
            $isOK = true;
            $exp = 0;
            if( $Expire )
            {
               $Expire = preg_replace('/\s*/','',strtolower($Expire));
               $match = array();
               $expires = 0;
               preg_match('/^(\d+)/',$Expire,$match);
               if( isset($match[1]) )
               {
                  $units = $match[1];
                  $match = array();
                  $days = 0;
                  preg_match('/([a-z]+)$/',$Expire,$match);
                  if( isset($match[1]) )
                  {
                     $increment = $match[1];
                     switch($increment)
                     {
                        case 'd' : $days = $units; break;
                        case 'w' : $days = $units * 7; break;
                        case 'm' : $days = $units * 30; break;
                        case 'h' : $days = $units / 24; break;
                        case 'y' : $days = $units * 365.25; break;
                     }
                  }
                  if( $days < 0 ) { $days = 0; }
                  if( $days ) { $expires = time() + ( $days * 24 * 60 * 60 ); }
               }
            }
            $time = time();
            if( headers_sent() )
            {
               $exp = $expires>0 ? ('; expires='.preg_replace('/\s[\+\-]*\d*$/',' GMT',date('r',$expires))) : '';
               echo "<script>document.cookie='$CookieName=$time$exp;'</script>";
            }
            else { setcookie($CookieName,time(),$expires,'/'); }
         }
      }
      if( ! $isOK ) { ShowLogInForm(); }
   }
   else { ShowLogInForm(); }
}

function ShowLogInForm()
{
   echo <<<LOGINFORM
<form method="post" enctype="multipart/form-data" action="{$_SERVER['PHP_SELF']}">
<div style="display:table; margin:.5in auto;">
<h3>
Log In
</h3>
<p>
Username<br><input type="text" name="un" style="width:200px; box-sizing:border-box;">
</p>
<p>
Password<br><input type="password" name="pw" style="width:200px; box-sizing:border-box;">
</p>
<p>
<input type="submit" value="Log In" style="width:200px; box-sizing:border-box;">
</p>
</div>
</form>
LOGINFORM;
   exit;
} // function ShowLogInForm()
?>

Customization:

If the data file location you have decided on is not USMdata/USM.txt, then replace USMdata/USM.txt with the correct location.

Customization of USM_monitor.php is complete.

USM_dashboard.php

Now, let's customize USM_dashboard.php. Here is the PHP script source code.

<?php
/*
Ultra-Simple Membership
Dashboard Unit
Version 1.0
November 24, 2019
Will Bontrager Software LLC
https://www.willmaster.com/
*/

/* *** Customizations *** */
// Three places to customize.

// Place 1.
// Specify the location of the membership data file. 
//    This must be identical to the location specified 
//    in the USM_monitor.php web page access monitor file.
// Specify the file's server location, not its URL.
// The directory and file must be writable by PHP.

$MemberDataFile = "USMdata/USM.txt";

// Places 2 and 3.
// Specify the username and the password for logging 
//    into the dashboard.
// The password may be encrypted. If not encrypted, 
//    the password may not be exactly 40 characters 
//    long. If encrypted, it muste be sha1 encrypted. 
//    (The tool at 
//    https://www.willmaster.com/secure/encrypt.php 
//    may be used to encrypt the password.)

$Username = "change_username";
$Password = "e9c28e8b9cabca75ef30a4150c80dd1c7725306d";

/* *** Customization End *** */

mb_regex_encoding('UTF-8');
mb_internal_encoding('UTF-8');
ini_set('display_errors',1);
error_reporting(E_ALL);
if( ! ini_get('date.timezone') ) { date_default_timezone_set('UTC'); }
$LoginForm = false;
$Dashboardmcookiename = 'USM_dashboard_cookie';
$DashboardCookieExpire = time() + intval( 365.25 * 24 * 60 * 60 );
if( empty($_COOKIE[$Dashboardmcookiename]) )
{
   if( isset($_POST['un']) and strlen($_POST['un'])>0 and $_POST['pw'] and strlen($_POST['pw'])>0 )
   {
      $_POST['un'] = trim($_POST['un']);
      $_POST['pw'] = trim($_POST['pw']);
      $Username = strtolower($Username);
      $un = strtolower($_POST['un']);
      if( $Username != $un ) { $LoginForm = true; }
      else
      {
         if( strlen($Password) != 40 )
         {
            if( $Password != $_POST['pw'] ) { $LoginForm = true; }
         }
         else
         {
            $sha1pw = sha1(trim($_POST['pw']));
            if( $Password != $sha1pw ) { $LoginForm = true; }
         }
      }
      if( ! $LoginForm ) { setcookie($Dashboardmcookiename,time(),$DashboardCookieExpire); }
   }
   else { $LoginForm = true; }
}
$Global = array();
$Global['memlist'] = '';
$Global['mcookiename'] = '';
$Global['mcookielife'] = '';
$Global['mlifeperiod'] = 'd';
$Global['Members'] = array();
$Global['notice'] = array();
if( ! $LoginForm )
{
   $MemberDataFile = trim($MemberDataFile);
   if( strpos($MemberDataFile,'/')===0 )
   {
      $MemberDataFile = preg_replace( '/^'.preg_quote($_SERVER['DOCUMENT_ROOT'],'/').'/', $_SERVER['DOCUMENT_ROOT'], $MemberDataFile );
      $MemberDataFile = "{$_SERVER['DOCUMENT_ROOT']}$MemberDataFile";
      $MemberDataFile = preg_replace('!//+!','/',$MemberDataFile);
   }
   $Global['Members'] = MakeDataFromMemberInfo($Global['memlist'],@file($MemberDataFile));
   if( isset($_POST['updated']) )
   {
      $Global['notice'][] = 'Updating&nbsp;&hellip;';
      $Global['NewMembers'] = array();
      $Global['mcookiename'] = preg_replace('/\W/','',$_POST['mcookiename']);
      $Global['mcookielife'] = intval(preg_replace('/\D/','',$_POST['mcookielife']));
      $Global['mlifeperiod'] = $_POST['mlifeperiod'];
      $Global['NewMembers'][] = "{$Global['mcookiename']}\t{$Global['mcookielife']}{$Global['mlifeperiod']}";
      foreach( preg_split('/[\r\n]+/',trim($_POST['memlist'])) as $line )
      {
         $line = trim($line);
         if( preg_match('/\s/',$line) < 1 )
         {
            if( isset($Global['Members'][$line]) ) { $Global['NewMembers'][] = "$line\t{$Global['Members'][$line]}"; }
            else { $Global['notice'][] = "New member username $line not recorded because no password provided."; }
            continue;
         }
         list($un,$pw) = preg_split('/\s+/',$line,2);
         $pw = sha1($pw);
         $Global['NewMembers'][] = "$un\t$pw";
      }
      $Global['notice'][] = '&hellip;&nbsp;done.';
      file_put_contents($MemberDataFile,implode("\n",$Global['NewMembers']));
      $Global['Members'] = MakeDataFromMemberInfo($Global['memlist'],$Global['NewMembers']);
   }
}

function MakeDataFromMemberInfo(&$memlist,$memarray)
{
   global $Global;
   $expire = '';
   $list = array();
   $memlist = array();
   if( ! is_array($memarray) ) { $memarray = array(); }
   if( count($memarray) ) { $Global['mcookiename'] = trim(array_shift($memarray)); }
   if( preg_match('/\s/',$Global['mcookiename']) ) { list($Global['mcookiename'],$expire) = preg_split('/\s/',$Global['mcookiename'],2); }
   if( ! count($memarray) ) { $memarray = array(); }
   $match = array();
   preg_match('/^(\d+)/',$expire,$match);
   if( isset($match[1]) )
   {
      $Global['mcookielife'] = $match[1];
      $match = array();
      if( preg_match('/([a-z]+)$/',$expire,$match) ) { $Global['mlifeperiod'] = $match[1]; }
   }
   $retval = array();
   if( count($memarray) )
   {
      foreach( $memarray as $line )
      {
         if( strpos($line,"\t") === false ) { continue; }
         list($un,$pw) = explode("\t",trim($line),2);
         $list[] = $un;
         $retval[$un] = $pw;
      }
   }
   $memlist = implode("\r\n",$list);
   return $retval;
} # function MakeDataFromMemberInfo()
?><!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ultra-Simple Membership Dashboard</title>
<style type="text/css">
* { box-sizing:border-box; }
html, body { font-size:100%; font-family:sans-serif; }
.nowrap { white-space:nowrap; }
.bold { font-weight:bold; }
.italic { font-style:italic; }
.underline { text-decoration:underline; }
input, textarea { width:100%; font-size:1em; }
input[type="text"], input[type="password"], textarea { border:1px solid #ccc; padding:3px; border-radius:3px; font-family:sans-serif; }
#content { max-width:650px; margin:.5in auto; background-color:transparent; }
</style>
</head>
<body><div id="content">
<form method="post" enctype="multipart/form-data" action="<?php echo($_SERVER['PHP_SELF']); ?>">
<div style="float:left; margin-right:1em;"><a href="https://www.willmaster.com/"><img src="https://www.willmaster.com/images/wmlogo_icon.gif"></a></div>
<h1 style="padding-top:5px; margin-bottom:2em;">Ultra-Simple Membership</h1>
<div style="clear:left;"></div>

<?php if( count($Global['notice']) ): ?>
<div style="border:3px double red; padding:1em; margin:.5in 0;">
<p class="bold">Notice:</p>
<ul>
<li><?php echo(implode('</li><li>',$Global['notice'])) ?></li>
</ul>
</div>
<?php endif; ?>

<?php if( $LoginForm ): ?>

<h3>
Log In
</h3>
<p>
Username<br><input type="text" name="un">
</p>
<p>
Password<br><input type="password" name="pw">
</p>
<p>
<input type="submit" value="Log In">
</p>

<?php else: ?>

<h1 style="position:relative; top:-1em;">Dashboard</h1>
<h3>
Member Cookie
</h3>
<p>
Member cookie name<br><input type="text" name="mcookiename" value="<?php echo($Global['mcookiename']) ?>"
</p>
<p>
Member cookie expires in (0 or blank for expiration when browser is exited)<br><input type="text" name="mcookielife" style="width:3em; text-align:center;" value="<?php echo($Global['mcookielife']) ?>"> 
<select name="mlifeperiod">
<option value="h"<?php if($Global['mlifeperiod']=='h'){echo(' selected="selected"');} ?>>hours</option>
<option value="d"<?php if($Global['mlifeperiod']=='d'){echo(' selected="selected"');} ?>>days</option>
<option value="w"<?php if($Global['mlifeperiod']=='w'){echo(' selected="selected"');} ?>>weeks</option>
<option value="m"<?php if($Global['mlifeperiod']=='m'){echo(' selected="selected"');} ?>>months</option>
<option value="y"<?php if($Global['mlifeperiod']=='y'){echo(' selected="selected"');} ?>>years</option>
</select>
</p>
<h3>
Member List
</h3>
<p>
Specify member usernames and passwords, both on the same line separated with one or more spaces and/or tabs. Usernames may not have any spaces. Passwords may be any series of characters. When updating the member list, previously assigned passwords will be invisible and won't be changed unless you type something in for a new password.
<br>
<textarea style="height:2in;" name="memlist"><?php echo($Global['memlist']."\n") ?></textarea>
</p>
<h3>
Update
</h3>
<p>
<input type="Submit" value="Update Information" name="updated">
</p>

<?php endif; ?>

</form>
<p style="margin-top:3em; border-top:1px solid #999; padding-top:.25em; display:table;">Copyright 2019 <a href="https://www.willmaster.com/">Will Bontrager Software LLC</a></p>
</div>
</html>

Customizations:

There are three places to customize.

Place 1
If the data file location you have decided on is not USMdata/USM.txt, then replace USMdata/USM.txt with the correct location. This must be the same value as specified when the previous script was customized.

Place 2
Replace change_username with a username to log into the Ultra-Simple Membership dashboard.

Place 3
Replace e9c28e8b9cabca75ef30a4150c80dd1c7725306d with either a plain text password or a password encrypted with SHA1. Plain text passwords may not be exactly 40 characters long because that is the length of a SHA1 encryption. To optionally encrypt your password, you may use this 40-character sha1 encryption form.

Customization of USM_dashboard.php is complete.

Uploading USM_monitor.php and USM_dashboard.php

Upload the two PHP scripts into the directory you decided on earlier.

Verify the subdirectory for the location of the data file exists. It must be writable by PHP. Generally, writable is the default, but some servers need subdirectories to have 777 permissions.

Using the Membership Software

With the installation complete, inserting one line of PHP code into web pages will change those page into member pages.

Here is the line (needs one customization).

<?php include($_SERVER["DOCUMENT_ROOT"] . "/one/two/USM_monitor.php") ?>

Replace one/two with the subdirectory path to where USM_monitor.php is installed.

That's all it takes to convert a regular web page into a member page.

Once the two PHP scripts are installed, it is both easy and simple to add or delete members through the dashboard. And one line of code converts a public web page into a member-only page.

(This article first appeared with an issue of the Possibilities newsletter.)

Will Bontrager

Was this article helpful to you?
(anonymous form)

Support This Website

Some of our support is from people like you who see the value of all that's offered for FREE at this website.

"Yes, let me contribute."

Amount (USD):

Tap to Choose
Contribution
Method

All information in WillMaster Library articles is presented AS-IS.

We only suggest and recommend what we believe is of value. As remuneration for the time and research involved to provide quality links, we generally use affiliate links when we can. Whenever we link to something not our own, you should assume they are affiliate links or that we benefit in some way.

How Can We Help You? balloons
How Can We Help You?
bullet Custom Programming
bullet Ready-Made Software
bullet Technical Support
bullet Possibilities Newsletter
bullet Website "How-To" Info
bullet Useful Information List

© 1998-2001 William and Mari Bontrager
© 2001-2011 Bontrager Connection, LLC
© 2011-2024 Will Bontrager Software LLC