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!

Easy Member

I rather enjoy making membership software.

When a long-time acquaintance expressed a need for an Easy Member solution, it was an excuse for me to make one. Easy Member is the result.

There are two PHP scripts to upload. Also a log-in form. And each member page gets a few lines of either PHP or JavaScript, depending on whether the member page can run PHP.

(In other words, the members area can work even with *.html or other non-PHP web pages.)

It is easier to get an Easy Member site installed and set up than any other self-install membership software I've seen.

  1. All settings, including the list of members, are on one dashboard page.

  2. Member lists contain only usernames and passwords.

  3. No MySQL database is used.

Passwords are respected.

  1. Member passwords are automatically encrypted with one-way encryption.

  2. After assigning a password, it is never again displayed in the dashboard (or anywhere else).

  3. Because passwords are one-way encrypted, the plain text original can not be retrieved. To change a password, it must be completely replaced.

Here is a screenshot of the dashboard so you can see how easy it is to use.

The usernames and encrypted passwords are in a plain text file stored at a location on the server that you specify. Passwords are encrypted. To make the file (and the entire directory) even more secure, use the technique described in the Uncrackable Directory Block blog post.

So you know what to expect, the username/passwords file looks something like this.

mycookie 2 m https://example.com/pages/login.php
will@example.com fffd86fb78a56a5145edsss9dcb00c78581ccae5
FriendlyFriend eef999fb78a56a5145ed7739dcb00c78581c544f
totallyCool 8efd855578a56a5145ed7739dcb00c78581c5312

There is nothing you need to do with the contents of the file. If you view your own file, the first line contains the cookie and log-in URL information. The rest is lines of usernames and encrypted passwords.

Let's go ahead and install Easy Member.

Installing the Easy Member PHP Scripts

There are two PHP scripts to install. They both need to be in the same directory on your server. The directory must be accessible with a browser.

We will do the dashboard script first. Then the log-in script.

The dashboard script:

The dashboard script has two places to customize. Notes follow the source code.

<?php
/*
Easy Member Software
- Dashboard Module -
Version 1.0
September 19, 2020
Will Bontrager Software LLC
https://www.willmaster.com/
*/

/* *** Customizations *** */
// Two places to customize.

// Place 1.
/// Specify the location of the membership data file. 
//     This must be identical to the location specified 
//     in the EM_dashboard.php dashboard file.
// The value specified here must be the same as the 
//     $MemberDataFile specified in the Log In Module

$MemberDataFile = "EMdata/EM.txt";

// Place 2.
// 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, 
//     which is exactly 40 characters long.
// The tool at 
//     https://www.willmaster.com/secure/encrypt.php
//     may be used to encrypt the password.

$Username = "change_login_credentials";
$Password = "8efd86fb78a56a5145ed7739dcb00c78581c5375";

/* *** 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'); }
$Global = array();
$Global['mcookiename'] = '';
$Global['mcookielife'] = '';
$Global['mlifeperiod'] = 'd';
$Global['mloginpage'] = '';
$Global['Members'] = array();
$Global['notice'] = array();
$Global['MemberDataFile'] = trim($MemberDataFile);
$LoginForm = false;
$Dashboardmcookiename = 'EM_dashboard_cookie';
$DashboardCookieExpire = time() + intval( 365.25 * 24 * 60 * 60 );
if( isset($_POST['login']) )
{
   if( isset($_POST['un']) and strlen($_POST['un'])>0 and isset($_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 )
      {
         $tm = time();
         $_COOKIE[$Dashboardmcookiename] = $tm;
         setcookie($Dashboardmcookiename,$tm,$DashboardCookieExpire);
      }
   }
   else
   {
      unset($_COOKIE[$Dashboardmcookiename]);
      setcookie($Dashboardmcookiename,0,-1);
      $LoginForm = true;
   }
}
if( empty($_COOKIE[$Dashboardmcookiename]) ) { $LoginForm = true; }
if( ! $LoginForm )
{
   if(strpos($Global['MemberDataFile'],'/')===0)
   {
      $Global['MemberDataFile'] = preg_replace('/^'.preg_quote($_SERVER['DOCUMENT_ROOT'],'/').'/','',$Global['MemberDataFile']);
      $Global['MemberDataFile'] = "{$_SERVER['DOCUMENT_ROOT']}{$Global['MemberDataFile']}";
   }
   else { $Global['MemberDataFile'] = __DIR__ . "/{$Global['MemberDataFile']}"; }
   if( isset($_POST['updated']) )
   {
      $Global['memholderlist'] = array();
      ReadMemberData($Global['memholderlist']); # To get and hold any passwords belonging to members.
      $Global['notice'][] = 'Updating&nbsp;&hellip;';
      $Global['mcookiename'] = preg_replace('/\W/','',$_POST['mcookiename']);
      $Global['mcookielife'] = intval(preg_replace('/\D/','',$_POST['mcookielife']));
      $Global['mlifeperiod'] = preg_replace('/[^hdwmy]/','',$_POST['mlifeperiod']);
      $Global['mloginpage'] = trim($_POST['mloginpage']);
      $Global['Members'] = array();
      foreach( preg_split('/[\r\n]+/',trim($_POST['memlist'])) as $line )
      {
         $line = trim($line);
         if( preg_match('/ /',$line) < 1 )
         {
            if( isset($Global['memholderlist'][$line]) ) { $Global['Members'][$line] = $Global['memholderlist'][$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['Members'][$un] = $pw;
      }
      WriteMemberData($Global['Members']);
      $Global['notice'][] = '&hellip;&nbsp;done.';
   }
   else { ReadMemberData($Global['Members']); } # For dashboard page.
}

function ReadMemberData(&$memlist)
{
   global $Global;
   if( ! file_exists($Global['MemberDataFile']) ) { return; }
   foreach( file($Global['MemberDataFile']) as $ln )
   {
      $line = trim($ln);
      if( strpos($line,"\t")===false )
      {
         $ta = preg_split('/\s+/',$line);
         if( count($ta)==2 ) { $memlist[$ta[0]] = $ta[1]; }
      }
      else { list($Global['mcookiename'],$Global['mcookielife'],$Global['mlifeperiod'],$Global['mloginpage']) = explode("\t",$line); }
   }
} # function ReadMemberData()

function WriteMemberData($memlist)
{
   global $Global;
   $f = fopen($Global['MemberDataFile'],'w');
   fputs($f,"{$Global['mcookiename']}\t{$Global['mcookielife']}\t{$Global['mlifeperiod']}\t{$Global['mloginpage']}\n");
   foreach( $memlist as $k => $v ) { fputs($f,"$k $v\n"); }
   fclose($f);
} # function WriteMemberData()

?><!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>Easy Member Software 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; }
select { font-size:1em; }
input, textarea { width:100%; font-size:1em; }
input[type="text"], input[type="number"], input[type="password"], textarea { border:1px solid #999; padding:.25em; border-radius:5px; 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;">Easy Member</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" name="login" value="Log In">
</p>

<?php else: ?>

<h1 style="position:relative; top:-1em; font-weight:normal;">Dashboard</h1>

<h3>
URL of Member Log-in Page
</h3>
<p>
The URL where members log in<br><input type="text" name="mloginpage" value="<?php echo($Global['mloginpage']) ?>"
</p>

<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="number" name="mcookielife" style="width:4em; 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 style="margin-bottom:3px;">
Specify member username and password sets separated with a space or tab &mdash; one set per line. Usernames, no spaces. Passwords may have any 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.
</p>
<textarea style="height:2in;" name="memlist"><?php echo(implode("\n",array_keys($Global['Members']))."\n") ?></textarea>
<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 2020 <a href="https://www.willmaster.com/">Will Bontrager Software LLC</a></p>
</div>
</html>

Notes —

There are two places to customize.

  1. In the source code, you'll see:

    $MemberDataFile = "EMdata/EM.txt";
    

    Replace EMdata/EM.txt with the location for the membership data file.

    The location needs to be relative to the PHP script (no leading "/" character). A newly-created subdirectory of where the script is running is a good place to specify.

    With the example EMdata/EM.txt in the above code, the membership data file is in the EMdata subdirectory and the file EM.txt is the file name.

    Note:  The very same value you specify for the file location in this script must also be specified in the log-in script further below.

  2. Also in the source code, you'll see:

    $Username = "change_login_credentials";
    $Password = "8efd86fb78a56a5145ed7739dcb00c78581c5375";
    

    Replace change_login_credentials with a username for your dashboard login.

    Replace 8efd86fb78a56a5145ed7739dcb00c78581c5375 with a password for your dashboard login. You may choose to specify one of two types of passwords.

    1. A plain text password that is either less than or more than 40 characters long — not exactly 40 characters.

    2. A sha1-encrypted password (which is exactly 40 characters long). The form at https://www.willmaster.com/secure/encrypt.php may be used to encrypt the password.

When the dashboard script has been updated, save the file as easymemberDashboard.php or other *.php file name you prefer. (These instructions assume easymemberDashboard.php is the file name.)

Upload easymemberDashboard.php to your server and make a note of its URL — you will use the URL to access the dashboard.

The dashboard control panel

Verify that the subdirectory for the membership data file exists.

Then, put the URL to easymemberDashboard.php into your browser and log in with the username and password you specified above.

Now, you'll fill in a few blanks.

  1. URL of Member Log-in Page

    Specify the URL of the web page that will contain the member log-in form.

  2. Member Cookie

    There are two sections here, the cookie name and how long the cookie shall stay in the browser.

    1. The cookie name needs to begin with a letter. The rest of the name may consist of any alphanumeric characters and/or underscore characters.

    2. Cookies can be specified to last any number of hours, days, weeks, months, or years. If you wish the cookie to expire when the browser is exited, specify 0 for the number field.

  3. Member List

    Specify at least one username and password so the log-in form can be tested. (The log-in form how-to is further below.)

    The username may not contain any spaces.

    The password may optionally contain spaces, and it may be as long as the person wants it to be (within reason; don't try a password as long as the content of the War and Peace book).

Tap the "Update…" button to store the control panel information.

Now, let's install the log-in script. (After that, the log-in form.)

The log-in script:

The log-in script has one place to customize. Notes follow the source code.

<?php
/*
Easy Member Software
- Log In Module -
Version 1.0a
October 10, 2020
Debug update, can now have only one member; v1.0 needed two or more.
Version 1.0, September 19, 2020
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 EM_dashboard.php dashboard file.
// The value specified here must be the same as the 
//     $MemberDataFile specified in the Dashboard Module

$MemberDataFile = "EMdata/EM.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'],'/').'/','',$MemberDataFile);
   $MemberDataFile = "{$_SERVER['DOCUMENT_ROOT']}$MemberDataFile";
}
else { $MemberDataFile = __DIR__ . "/$MemberDataFile"; }
$mcookiename = $mcookielife = $mlifeperiod = $mloginpage = false;
$Members = array();
if( file_exists($MemberDataFile) )
{
   foreach( file($MemberDataFile) as $ln )
   {
      $line = trim($ln);
      if( strpos($line,"\t")===false )
      {
         $ta = preg_split('/\s+/',$line);
         $Members[$ta[0]] = $ta[1];
      }
      else { list($mcookiename,$mcookielife,$mlifeperiod,$mloginpage) = explode("\t",$line); }
   }
}
if( count($Members) < 1 )
{
   echo '<p>Missing or blank data file, or unable to find members in it.</p>';
   exit;
}
$match = false;
$memname = strtolower(trim($_POST['un']));
$mempass = sha1(trim($_POST['pw']));
foreach( $Members as $n => $p )
{
   if( $memname == strtolower($n) )
   {
      if( $p == $mempass )
      {
         $match = true;
         break;
      }
   }
}
if( ! $match ) { GoToNewPagePHP($mloginpage); }
$expires = 0;
$i = 24 * 60 * 60;
switch($mlifeperiod)
{
   case 'y' : $expires = ($i * 365.25); break;
   case 'm' : $expires = ($i * 30.5); break;
   case 'w' : $expires = ($i * 7); break;
   case 'd' : $expires = $i; break;
   default  : $expires = 60*60;
}
$expires *= $mcookielife;
if( $expires )
{
   $expires = time()+intval($expires);
   setcookie($mcookiename,time(),$expires);
}
else { setcookie($mcookiename,time()); }
GoToNewPagePHP( isset($_POST['url']) ? $_POST['url'] : '/' );
function GoToNewPagePHP($url)
{
   if( headers_sent() ) { echo "<script>location.href='$url';</script>"; }
   else { header("Location: $url"); }
   exit;
}
?>

Notes —

There is one place to customize.

  • In the source code, you'll see:

    $MemberDataFile = "EMdata/EM.txt";
    

    Replace EMdata/EM.txt with the same location for the membership data file as you specified in the easymemberDashboard.php dashboard script further above.

When the log-in script has been updated, save the file as easymember.php or other *.php file name you prefer. (These instructions assume easymember.php is the file name.)

Upload easymember.php to your server into the directory where the easymemberDashboard.php dashboard script is located. Make a note of its URL — the log-in form will need it.

The Log-in Form

Here is source code for a log-in form. Notes follow.

<form method="post" action="https://example.com/mem/easymember.php">
<input type="hidden" name="url" value="https://example.com/pages/page.php">
<p>
Username <input type="text" name="un" style="width:200px;">
</p><p>
Password <input type="password" name="pw" style="width:200px;">
</p><p>
<input type="submit" value="Log In" style="width:200px;">
</form>

Notes —

There are two places to customize.

  1. In the form source code, replace https://example.com/mem/easymember.php with the URL to your installation of the easymember.php script.

  2. In the form source code, replace https://example.com/pages/page.php with the URL to the landing page in your member area.

Put the form into a web page so members can log in.

The form may be designed as you wish. But the form field names need to have the same values as they have in the above source code.

Load the web page with the log-in form in your browser. Log in with the username and password you specified earlier in the Easy Member dashboard.

Individual Member Pages

Each member page gets a few lines of code to check the member cookie when the page loads into a browser.

The code could be PHP code or JavaScript code. Use the JavaScript code only if you can't use the PHP code.

The reason to use the PHP code when you can is because the JavaScript code won't work for robots and for browsers with JavaScript turned off.

The PHP code:

This PHP code needs to be in all member pages, preferably at the top of the page so no content is sent to the browser when the member cookie is absent.

In the following code, replace https://example.com/pages/login.php and mycookie with, respectively, the log-in page URL and the cookie name that you specified in the Easy Member dashboard.

<?php
$loginURL = "https://example.com/pages/login.php";
$cookiename = "mycookie";
if(empty($_COOKIE[$cookiename]))
{
   if( headers_sent() ) { echo "<script>location.href='$loginURL';</script>"; }
   else { header("Location: $loginURL"); }
   exit;
}
?>

The JavaScript code:

When PHP code can't be used, JavaScript can suffice. But be aware that robots and browsers with JavaScript turned off will have access to the member page.

The JavaScript code needs to be in all member pages, preferably as close to the top of the page as you can get it. The top-of-page reason is for both speed and so no or little content is sent to the browser when the member cookie is absent.

In the following code, replace https://example.com/pages/login.php and mycookie with, respectively, the log-in page URL and the cookie name that you specified in the Easy Member dashboard.

<script style="text/javascript">
function Easy_Member_Monitor()
{
   var loginURL = "https://example.com/pages/login.php";
   var cookiename = "mycookie";
   if(document.cookie.indexOf(cookiename)<0){location.href=loginURL;}
}
Easy_Member_Monitor();
</script>

Using Easy Member

Now that the member software is installed, simply add and delete member usernames and passwords in the Easy Member dashboard as appropriate for your needs.

If you add member pages, remember to add the few lines of PHP (or JavaScript) to verify the cookie exists.

(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