assign($params['assign'], $content) : $content; return $ret; } else { $protected_msg = ( # we add ability to override protected_msg from {protect protected_msg='some message'} isset($params['protected_msg']) ? $params['protected_msg'] : cms_utils::get_app_data('_PP_Prot_Msg') ); if (isset($protected_msg)) { $ret = isset($params['assign']) ? $smarty->assign($params['assign'], $protected_msg) : $protected_msg; return $ret; } } } } } function smarty_cms_function_page_protect($params, &$template) { # initialize a few vars $smarty = $template->smarty; $gCms = cmsms(); $current_page_alias = cms_utils::get_current_alias(); $logout_alias = isset($params['logout_alias']) ? $params['logout_alias'] : $current_page_alias; $login_alias = isset($params['login_alias']) ? $params['login_alias'] : null; $assign_var = isset($params['assign']) ? $params['assign'] : 'pp_logged_in'; # some of the params have to be persistent through all the page request # so we use the same method as ModuleHint i.e. cms_utils Data Storage # flag to check if current user is authenticated $allow = cms_utils::get_app_data('_PP_Allow'); if (!isset($allow)) { $allow = false; } # timeout in minutes (cookie lifecycle). Null or 0 (zero) means off $timeout = cms_utils::get_app_data('_PP_TOut'); $use_timeout = cms_utils::get_app_data('_PP_useTOut'); if (!$timeout) { if(isset($params['timeout'])) { $interval = $params['timeout'] * 60; } $timeout = ( isset($interval) ? time() + $interval : 0 ); $use_timeout = ( $timeout > 0 ); cms_utils::set_app_data('_PP_TOut', $timeout); cms_utils::set_app_data('_PP_useTOut', $use_timeout); } $cookie_name = cms_utils::get_app_data('_PP_CookieN'); if (!isset($cookie_name)) { $cookie_name = isset($params['cookie_name']) ? $params['cookie_name'] : 'pp_auth'; cms_utils::set_app_data('_PP_CookieN', $cookie_name ); } ##### messages ##### $protected_msg = cms_utils::get_app_data('_PP_Prot_Msg'); if (!isset($protected_msg)) { $protected_msg = isset($params['protected_msg']) ? $params['$protected_msg'] : $protected_msg; cms_utils::set_app_data('_PP_Prot_Msg', $protected_msg ); } $error_msg = cms_utils::get_app_data('_PP_Error_Msg'); if (!isset($error_msg)) { $error_msg = isset($params['error_msg']) ? $params['error_msg'] : 'The password is not correct.'; cms_utils::set_app_data('_PP_Error_Msg', $error_msg ); } $welcome_msg = cms_utils::get_app_data('_PP_Welcome_Msg'); if (!isset($welcome_msg)) { $welcome_msg = isset($params['welcome_msg']) ? $params['welcome_msg'] : 'Please enter the password to access this page.'; cms_utils::set_app_data('_PP_Welcome_Msg', $welcome_msg ); } ##### messages end ##### if (!isset($params['passwords'])) { $passwords = cms_utils::get_app_data('_PP_Pass'); } else { $passwords = &$params['passwords']; } if (!is_array($passwords)) { if (strpos($passwords, ',') === false) { $passwords = array($passwords); } else { $passwords = explode(',', $passwords); } } cms_utils::set_app_data('_PP_Pass', $passwords); ##### process requests and Cookies ##### $cookie_found = false; # logout if(isset($_POST['pp_logout'])) { # clear pass from cookie and redirect setcookie($cookie_name, '', 0, '/'); $allow = false; redirect_to_alias($logout_alias); } # process pass if (isset($_POST['pp_password'])) { $pass = $_POST['pp_password']; if ( !in_array($pass, $passwords) ) { $msg = $error_msg; $allow = false; } else { if ($use_timeout) { # we set cookie here #setcookie($cookie_name, md5($username . '%pp%' . $pass), $timeout, '/'); # todo setcookie($cookie_name, md5($pass), $timeout, '/'); } $allow = true; # @since 1.1 if (!isset($login_alias)) { redirect_to_alias($login_alias); } } } else { if ($use_timeout) { # check if cookie exists and is set if (!isset($_COOKIE[$cookie_name])) { $msg = ''; $allow = false; } foreach($passwords as $one) { if (isset($_COOKIE[$cookie_name]) && $_COOKIE[$cookie_name] == md5($one)) { $cookie_found = true; $allow = true; # so we have a valid request: extend timeout setcookie($cookie_name, md5($one), $timeout, '/'); break; } } if (!$cookie_found) { $allow = false; # may very well be redundant but hey!!! we clear any pending messages anyway $msg = ''; } } } ##### end process requests and Cookies ##### cms_utils::set_app_data('_PP_Allow', $allow); ##### actions ##### # @since 1.2 $action = isset($params['action']) ? $params['action'] : 'default'; switch ($action) { case 'form': { # common to both buttons $button_id = isset($params['button_id']) ? 'id="' . $params['button_id'] . '" ' : ''; $button_class = isset($params['button_class']) ? 'class="' . $params['button_class'] . '" ' : ''; if (!$allow) { $login_btn = isset($params['login_btn']) ? $params['login_btn'] : 'Login'; $form_id = isset($params['form_id']) ? 'id="' . $params['form_id'] . '" ' : ''; $form_class = isset($params['form_class']) ? 'class="' . $params['form_class'] . '" ' : ''; $in_pass_id = isset($params['in_pass_id']) ? 'id="' . $params['in_pass_id'] . '" ' : ''; $in_pass_class = isset($params['in_pass_class']) ? 'class="' . $params['in_pass_class'] . '" ' : ''; # @since 1.2 -> avoid warnings $msg = isset($msg) ? $msg : ''; $html = ''; $html .= '
'; $html .= '

'. $welcome_msg . '

'; $html .= '

' . $msg . '

'; $html .= ''; $html .= ''; $html .= '
'; } else { $logout_btn = isset($params['logout_btn']) ? $params['logout_btn'] : 'Logout'; $html = ''; $html .= '
'; $html .= ''; $html .= ''; } # @since 1.2 if (isset($params['assign_output'])) { $smarty->assign($params['assign_output'], $html); } else { $ret = $html; } } break; # default usage: has to be located on top of the template # OR preferably on the "Smarty data or logic that is specific to this page" field # otherwise you'll get smarty error: {protect} tag is unknown # also has to be the top-most tag of any sequence of calls case 'set': { # dummy action: so one can set persistent parameters without triggering other actions } break; # default actions: just register the smarty plugin case 'default': default: { # register with smarty # usage: {protect}Content you want to protect {/protect} $smarty->registerPlugin("block", "protect", "pp_protect"); } } # send a var to the calling template, either assigned name or defaults to {$pp_logged_in} $smarty->assign($assign_var, $allow); if( isset($ret) ) return $ret; # @since 1.2 -> if we come from forms action we may have $ret set } ##### Docs ##### function smarty_cms_help_function_page_protect() { $txt = <<<'EOT'
General
The Quick Way
Initializing
The Form Action
The Set Action
The Protect Tags
Snippets
Final Notes

What does this do?

This plugin allows you to protect a number pages with one or more passwords.

This plugin can be used on any number of pages, either by being set once per each page you want to protect, or by being set on a page template, allowing you to protect all pages connected to that template

How to use it?

As of version 1.2, this plugin can work in two different ways:

  • the typical way where you initialize the plugin either on the template, using the following tag {page_protect} on the very beginning of the template, and right before the{process_pagedata} if it exists, or on the field Smarty data or logic that is specific to this page* found on each page options tab;
  • a different faster way where you don't have to initialize the plugin, but with which you lose flexibility: use a minimal tag call with the form and check for a Smarty variable, $pp_logged_in by default, with some Smarty logic;

Note that these two methods are not mutually exclusive: one adds to the other.

* Note: this only works if the tag {process_pagedata} is present on the template and is called before any other content block.

What parameters does it take?

  • (optional) action - possible values:
    • 'default': the default action of the plugin which is to initialize itself;
    • 'form': show either the login form or the logout form, depending on current user state;
    • 'set': use this action to distribute persistent parameters though different tags on the same page (helps readability);
  • (optional) (persistent) login_alias - an existing page alias (defaults to no redirection): this will be used to redirect after login if needed;
  • (optional) (persistent) logout_alias - an existing page alias (defaults to current page i.e. the page where the plugin is being used): this will be used to redirect after logout;
  • (optional) (persistent) timeout - if set to a value higher then 0 it will set a cookie and use this value as minutes before login times out;
  • (optional) (persistent) cookie_name - the name of the cookie (defaults to pp_auth);
  • (optional) (persistent) welcome_msg - a message to be shown as a welcome text on the login form;
  • (optional) (persistent) protected_msg - a message to replace the protected content (defaults to no message at all);
  • (optional) (persistent) error_msg - an error message to be shown on password errors;
Exclusive to form action:
  • (optional) login_btn - text of the login button caption (defaults to Login);
  • (optional) logout_btn - text of the logout button caption(defaults to Logout;
  • (optional) form_id - login form id;
  • (optional) form_class - login form class;
  • (optional) in_pass_id - password input id;
  • (optional) in_pass_class - password input class;
  • (optional) button_id - both buttons id;
  • (optional) button_class - both buttons class;
Protect tag accepts only one parameter:
  • (optional) protected_msg - a message to replace the protected content (defaults to whatever was set on a previous persistent tag call, typically on the default action);

The Quick Use

As of version 1.2 the plugin has a new functionality which allows for a faster deployment of a secure page. Page Protect will assign a Smarty variable, $pp_logged_in by default, with a boolean value flagging whether the current user is logged in or not.

As an example:

{page_protect action='form' passwords='pass1'}


This is a simple way to hide the content of a page from non authorized users:

Use this on the page content!

    
{page_protect action='form' passwords='pass1'}
{if $pp_logged_in}
  The allowed content....
{else}
  Not Logged in!
{/if}
    

The previous snippet will show a form for non logged in users, along with the text "Not Logged in!"

For the logged in user will present a logout button, and "The allowed content....".


This is a simple way to hide the content of all pages with this template from non authorized users:

Use this on the main template!


{content assign='content'}
{page_protect action='form' passwords='pass1'}
{if $pp_logged_in}
  {$content}
{else}
  Not Logged in!
{/if}
    

The previous snippet will show a form for non logged in users, along with the text "Not Logged in!"

For the logged in user will present a logout button, and the content of the page.

Note: by using only this method, without initializing the plugin, you cannot use the {protect}{/protect} tags. To use them you need to initialize the plugin!

Initializing

In previous versions, the plugin needed to be initialized to work at all. As of version 1.2 the initialization is optional. However if the plugin is not initialized it will lose versatility. That doesn't mean that the quick setup, without the initialization, is not a valid setup. It is however a setup with less functionality, thus having its drawbacks.

Why Initialize At All

By initializing the plugin you will have registered with the Smarty engine a block tag, {protect}{/protect}, which allow you to protect large blocks of text easily.

How To Initialize

The initialization can be made through one of two methods, depending on what you want to protect. The most common scenarios are the following:

  • protecting a single page with a set of passwords;
  • protecting a number of pages with specific passwords (one or more but different sets) per page;
  • protecting a number of pages with the same set of passwords;
  • protecting different groups of pages with the same set of passwords per group, but different from group to group;

In the first two cases, the initialization should be made on each page, preferably on the field Smarty data or logic that is specific to this page* found on the page options tab.

Use one of these tags:

  • {page_protect}
  • {page_protect action='default'}

wich are equivalent.

You can also use this tag to add a few parameters except for action='set' and action='form' (and all form exclusive parameters as they are only pertinent to the form action and not persistent). Use:

  • {page_protect passwords='pass1[,pass2]...[,passn]'}
  • {page_protect action='default' passwords='pass1[,pass2]...[,passn]'}

* Note: this only works if the tag {process_pagedata} is present on the template and is called before any other content block.

Put this on the field Smarty data or logic that is specific to this page found on the page options tab:

    
{page_protect passwords='password1,passwor2,password3,passwordn'}
    

Alternatively, if you are not using the {process_pagedata} on your templates, you can still initialize the plugin, for a given page, by using the initialization tag on an extra content block which should be placed at the top of the template as the very first call.

Also alternatively, if you are not using the {process_pagedata} on your templates, you can still initialize the plugin, for a given template, by using the initialization tag on the top of the template as the very first. Keep in mind that all pages using that template will recognize the {protect}{/protect} tags. Also note that this method is also used for the 3rd and 4th scenarios, as it will be explained later.

Although you can, you don't need to set the passwords, nor any other parameters on the initialization tag: as most of the parameters are persistent through the same request, there is a special action, set, that can be used specifically to set persistent parameters anywhere on a template or content block (see more on the set action help tab).

Note: you cannot use {protect}{/protect} on the same content block where you initialized the plugin. The initialization won't be in effect yet and Smarty will not recognize the new tags at that point.

Note: you can use {protect}{/protect} on the same template where you initialized the plugin. However the {protect}{/protect} tags will have to be placed inside the <BODY>...</BODY> tags or the <BODY>...</BODY> tags, while the {page_protect} needs to be outside the <HTML>...</HTML> tags, or processed through {process_pagedata}.

It is important to understand the sequence by which CMSMS parses templates:

  • 1st: everything outside the <HTML>...</HTML> tags;
  • 2nd: everything inside the <BODY>...</BODY> tags;
  • 3rd: everything inside the <HEAD>...</HEAD> tags;

This means that each of these template areas is considered by CMSMS as a different block, and parsed tags and variables will be carried forward to the next in that sequence. It also guarantees that the tags {protect}{/protect} will be usable inside the <BODY>...</BODY> tags and the <BODY>...</BODY> tags, if properly initialized outside the <HTML>...</HTML> tags, particularly at the top of the template.

Finally in the last two scenarios, the initialization should be made on the template, preferably on the top of the template and outside the <HTML>...</HTML> tags.

If you only need to protect a number of pages with the same set of passwords, the 3rd case, you'll need only one extra template with the initialization tag. In the 4th case, where you need to protect different groups of pages with the same set of passwords per group, but different passwords from group to group, you may still use one template and set the passwords with some Smarty logic, but if you are not experienced with Smarty, then just create a template for each set of passwords, and assign the templates to the pages accordingly.

Put this on the top of your templates:

    
{page_protect passwords='password1,passwor2,password3,passwordn'}
    

For specific help on the other actions, and the protect block tags, check the respective action help tabs.

The Form Action

As of version 1.2, you can set all options on the tag call with this action. If you are using the quick way, this is all you need to set a Smarty variable which you can check anywhere on the template after this call.

Other than that just place the tag where you want a login/logout form. The default form action has default values for all form parameters, so the minimal tag is {page_protect action='form'}.

use {page_protect action='form'} to display the default login/logout form.

An example with all the parameters you can use to customize the form:

    
{* Do you really need all this?!!! A complete form call *}
{page_protect action='form' login_btn='Let Me In!' logout_btn='Bye Bye!' form_class='css_form' form_id='css_my_form' in_pass_id='css_passwrdid' in_pass_class='css_passwrd_class' button_id='css_btn_id' button_class='css_btn_class'}
    

As of version 1.2 any call to {page_protect action='...'}, with any action, including the default, will set a Smarty variable, which can be customized by the assign parameter, but which will default to $pp_logged_in by omission. This will be set to boolean TRUE whenever the current visitor is logged in and FALSE otherwise.

For specific help on the The Quick Way check the respective action help tab.

You can use any of the persistent parameters with the form action if needed. However the form specific parameters are not persistent.

Parameters exclusive to form action:
  • (optional) login_btn - text of the login button caption (defaults to Login);
  • (optional) logout_btn - text of the logout button caption(defaults to Logout;
  • (optional) form_id - login form id;
  • (optional) form_class - login form class;
  • (optional) in_pass_id - password input id;
  • (optional) in_pass_class - password input class;
  • (optional) button_id - both buttons id;
  • (optional) button_class - both buttons class;

The Set Action

This is a special action with the sole purpose of allowing you to set persistent parameters on different tag calls, helping a bit with the readability of the tags: just keep in mind that if you call it using the same parameter with different values, the last value will override all previous.

{* Using the 'set' action to spread parameters through multiple calls *}
{* redirect Home *}
{page_protect action='set' logout_alias='home'}
{* set the time before a login expires *} 
{page_protect action='set' timeout=10}
{* set the message to show in case the authentication fails *}
{page_protect action='set' error_msg='Oops! Wrong pass, mate! Check your notes...'}
{* setting all the above in a single tag call could lead to errors *}
    

What parameters does it take?

  • (optional) (persistent) login_alias - an existing page alias (defaults to no redirection): this will be used to redirect after login if needed;
  • (optional) (persistent) logout_alias - an existing page alias (defaults to current page i.e. the page where the plugin is being used): this will be used to redirect after logout;
  • (optional) (persistent) timeout - if set to a value higher then 0 it will set a cookie and use this value as minutes before login times out;
  • (optional) (persistent) cookie_name - the name of the cookie (defaults to pp_auth);
  • (optional) (persistent) welcome_msg - a message to be shown as a welcome text on the login form;
  • (optional) (persistent) protected_msg - a message to replace the protected content (defaults to no message at all);
  • (optional) (persistent) error_msg - an error message to be shown on password errors;

The Protect Tags

These tags are block smarty tags, and can be used several times on the page in pairs, i.e: an opening tag and a closing tag. The opening tag accepts only one parameter, the protected_msg which overrides the default one if set. This is a per occurrence tag, meaning that if it is set on the default or set actions it is persistent, but if set on a {protect} tag it affects only the tag where it is used and doesn't persist to the next occurrence.

Content wrapping tags example.

Use one of the following tags:

    
{protect}whatever content you want protected.{/protect} 
{protect protected_msg='well, you really should be logged in if you what to see the content'}whatever content you want protected.{/protect}
    

Note: without initializing the plugin, you cannot use the {protect}{/protect} tags.

Note: you cannot use {protect}{/protect} on the same content block where you initialized the plugin. The initialization won't be in effect yet and Smarty will not recognize the new tags at that point.

Protect tag accepts only one parameter:
  • (optional) protected_msg - a message to replace the protected content (defaults to whatever was set on a previous persistent tag call);

Code Snippets

The Quick Way

Use this anywhere on a template or a page content block:

    
{* This snippet of code can be used standalone; no need for an initialization tag *}    
{page_protect action='form' passwords='pass1'}
{if $pp_logged_in}
  The allowed content....
{else}
  Not Logged in!
{/if}
    

Initialization

Use this anywhere on the top of a template or on a page content block, preferably on the field Smarty data or logic that is specific to this page:

    
{* This tag initializes the plugin so that you can use the {protect}{/protect} tags *}    
{page_protect}
    

A more complex example. Use this anywhere on the top of a template or on a page content block, preferably on the field Smarty data or logic that is specific to this page:


{* Use smarty syntax to create an array *}
{$passwords=['pass1','pass2','pass3']}

{* Use smarty syntax to set a few messages into variables we can use to fill in the parameters *}
{$welcome_msg='Please enter your password'}
{$protected_msg='You really need to login to have access to this page.'}
{$error_msg='The password you entered is not correct. Please check carefully if the password is correct and try again.'}
  
{****************************************************************************** 
This tag initializes the plugin so that you can use the {protect}{/protect} tags.
Note the use of already set Smarty vars to pass values to some parameters. 
*******************************************************************************}    
{page_protect passwords=$passwords login_alias='home' logout_alias='bye-bye-page-alias' timeout=10 cookie_name='a_cookie_name' welcome_msg=$welcome_msg protected_msg=$protected_msg error_msg=$error_msg}
    

Using The Set Action

    
{* Using the 'set' action to spread parameters through multiple calls *}
{* redirect Home on logout *}
{page_protect action='set' logout_alias='home'}
{* set the time before a login expires *} 
{page_protect action='set' timeout=10}
{* set the message to show in case the authentication fails *}
{page_protect action='set' error_msg='Oops! Wrong pass, mate! Check your notes...'}
{* set the name of the login the check variable *}
{page_protect action='set' assign='logged_in'}
{* setting all the above in a single tag call could lead to errors *}

{* now we can check for our own named variable *}
{if $logged_in}
  The allowed content...
{else}
  Not Logged in!
{/if}

    

Using The Form Action

An example with all the parameters you can use to customize the form:

    
{* Do you really need all this?!!! A complete form call which doesn't output nothing because the assign_output parameter is being used *}
{page_protect action='form' login_btn='Let Me In!' logout_btn='Bye Bye!' form_class='css_form' form_id='css_my_form' in_pass_id='css_passwrdid' in_pass_class='css_passwrd_class' button_id='css_btn_id' button_class='css_btn_class' assign_output='login_form'}
{* by using assign_output='login_form' you can use {$login_form} several times on the template *}
{$login_form}
    

Using The Protect Block Tags

Use one of the following tags:

    
{protect}whatever content you want protected.{/protect} 
{protect protected_msg='well, you really should be logged in if you what to see the content'}whatever content you want protected.{/protect}
    

Passwords

The passwords parameter can accept a range of values, from a single password, a comma separated list of passwords, or an array of values:

      
{page_protect passwords='pass1'}
    

    
{page_protect passwords='pass1,'pass2','pass3'}
    

    
{* Use smarty syntax to create an array *}
{$passwords=['pass1','pass2','pass3']}

{* or *}
{$passwords[]='pass1'}
{$passwords[]='pass2'}
{$passwords[]='pass3'}

{* and use it as the value for the parameter passwords *}
{page_protect passwords=$passwords}

{* or *}
{page_protect action='set' passwords=$passwords}
    

Notes

Tags Order

The order by which the tags are called is extremely important: the default action (parameter action='default' which can be omitted) , when used, cannot be set on the same content block as the {protect}{/protect} tags, and should be called on the topmost block of the template. This tag registers a smarty block plugin {protect} which won't be recognized before being parsed once (and registered) by the Smarty engine. After this first call, all other calls don't have a specific order other than, of course, the opening and closing {protect}{/protect} tags.

Persistent Parameters

Some of the parameters used by this plugin are persistent for the duration of the request, that is to say, through all of the current rendered page. This means that you can set them once, knowing they will be used later on the same request on subsequent calls to the plugin. That also means that they can be changed on subsequent calls, if needed.

Passwords

Note: Unless you use an array to set the passwords, avoid the use of commas (,) and of vertical slashes (|) as password symbols as these are reserved to internal use and will unavoidably lead to passwords not being recognized by the plugin.

Additional Notes

If the timeout parameter is used, this plugin will generate a frontend cookie. By using this parameter you may be violating some countries laws of user privacy. Please make sure you provide a fair warning on the front pages if needed, or avoid using the timeout parameter, thus disabling the use of cookies. The only drawback of not using cookies is that the authentication only lasts for a single page request.

This plugin needs PHP version 5.3.

EOT; echo $txt; } function smarty_cms_about_function_page_protect() { $txt = <<<'EOT'

About

Version: 1.2

Author: Jo Morg (Fernando Morgado)

Another plugin made out of need. Enjoy!

History

To Do List

EOT; echo $txt; } ?>