Macrura

Password Protect Page

Recommended Posts

I have a client who is a record label and they need to have some pages for promoting albums, where there can be a password they give to a reviewer, so the reviewer can go to the URL, type in the password, and be able to view the content (which will be streaming audio and downloads of the album in question).

i have found some simple ways online to do this with PHp, but i'm wondering if there is a better/simple way to interact with PW session to achieve this.

The client doesn't want to have to add roles/users or deal with permissions...they just want to have an input field where they can put in the password for that album...

TIA,

Marc

Share this post


Link to post
Share on other sites

All the reviewers will have the same password for each album? Or each reviewer will have it's own password?

Share this post


Link to post
Share on other sites

All the reviewers will have the same password for each album? Or each reviewer will have it's own password?

Good question - another one could be whether the password should be time limited? So it will work for 48 hours then become obsolete, for example.

Share this post


Link to post
Share on other sites

It would be 1 password to access the album, everyone with the password would be able to access it;

this will be on a non search indexed subdomain of their main site, the links only given to the various press/reviewers.

after the promo period, they would unpublish the page, and we would use the redirects module to send incoming requests to a contact page;

Share this post


Link to post
Share on other sites

Did I understood right?

1 Page with only a Password form?

According to the password the user will be redirected to the common album?

How secure has the login to be?

I think the fastest way to achieve your needs would be a template with a input field -> site Password and the main content.

In the Template file you could do something like this:

<?php
// check for login before outputting markup
if($input->post->pass) {

 $pass = $input->post->pass;
 if($pass == $page->password_field) {
		 // login successful
		 $session->redirect($page->url);
 } else {
		 $session->login_error = 'Please check your Password';
 }
} ?>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Login</title>
</head>
<body>
<? if($input->post->pass) {
	 echo "<div class='error'>				
" . $session->login_error . "
		 </div>";
	 }?>		
<form method="post" action="./" accept-charset="UTF-8">

<input type="password" id="pass" name="pass" placeholder="Password" required />
	 <button type="submit" name="submit" class="btn btn-success btn-block">Login</button>
</form>

</body>
</html>
<?
die(); // don't go any further if not logged in
} // end !logged in
?>

Share this post


Link to post
Share on other sites

Thanks Luis, I really appreciate your post - this looks like a very simple/elegant way to do this - i'll report back as soon as i have a chance to integrate this.

-marc

Share this post


Link to post
Share on other sites

Hi Luis,

I've almost got this working, the main issue now is that the code seems to loop, and also i was getting an error because of the unmatched brace on the } "// end !logged in" line... maybe that's why this is not working?

so after you click the login button, you keep getting back to the login page, i guess because since it is all on the same template?

I tried an alternate idea of having only the login code on the template and then including the markup code for the page, contingent on being logged in, which works;

but i'm not sure this is necessary - and with this method i can't figure out how to throw the wrong password error...

thanks again for your advice and the code!

-marc

Share this post


Link to post
Share on other sites

Hey Marc,

How did you implemented the code?

Sorry for the error, I didn´t tested the code just copy and pasted the snippet and edited it in the browser.

Well my thoughts where the following:

New Page called Albums. -> Status Hidden to exclude from search and nav.

Children of Albums are the Password protected pages.

New Template called Album. -> works as template for these children.

Album template contains the following fields:

password

body

images

the template file should look something like this:

<- Password / login code ->

<- normal page code like head, foot and your assigned fields ->

So you create a new child and enter your wished password in the assigned password field.

After entering the password you should have access to the page.

Share this post


Link to post
Share on other sites

Hi Luis,

this is my temporary solution - it works for now, but i'm thinking i should do this with a session variable so that if the user refreshes the page or navigates away, and comes back, they don't have to re-enter the password; Also i need to provide an error message... thanks again for your help; I'll see if i can improve my knowledge/use of the api with respect to $input and $session...

<?php
if($page->album_password) {

   $pass = $page->album_password;    
   if($input->post->pass != $pass) { ?>

   <!DOCTYPE html>
   <html>
   <head>
   <meta http-equiv="content-type" content="text/html; charset=utf-8" />
   <title>Login to view <?php echo $page->album_title ?></title>
   </head>
   <body>

       <form method="post" action="./" accept-charset="UTF-8">
           <input type="password" id="pass" name="pass" placeholder="" />
           <button type="submit" name="submit" class="btn btn-success btn-block">Login</button>
       </form>

   </body>
   </html>

   <? } else {
   include("./inc/album.inc");
   }

   } else {
   include("./inc/album.inc");
   }
?>

Share this post


Link to post
Share on other sites

Should be fairly easy to add session support.

if($input->post->pass) $session->pass = $input->post->pass; 
if($page->album_password && $session->pass !== $page->album_password) {
 $page->body = $input->post->pass ? '<h3>Invalid Password</h3>' : '';
 $page->body .= file_get_contents("./inc/login-form.inc"); 
 include("./basic-page.php"); 
} else {
 include("./album.inc"); 
}
  • Like 2

Share this post


Link to post
Share on other sites

im also implementing pages protected only by a a password. The code here works, but like this the password isn't using any encryption. I tried to define the field as a password, and like this make it encrypted. But i dont know how to compare with the user input

i tried this, where password_salt is a password field for this page:

// this works: i got the input from the form password field
$pw2= $input->pass;
echo "<br />bd: " . $pw2;

// here i got the: Error: Exception: Method Password::match does not exist or is not callable in this context 
$pw3= $page->password_salt->match($pw2);
echo "<br />password_salt: " . $pw3;

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By MoritzLost
      I've been working with ProcessWire for a while now, and I've noticed that using Composer to manage dependencies and autoload external libraries isn't as prevalent in ProcessWire development as in other areas of PHP programming. I started out by using the default setup recommend in this blogpost. However, one major problem I have with this approach is that all external dependencies live in the webroot (the directory the server points to), which is unfavourable from a security standpoint and, in my opinion, just feels a bit messy.
      In this tutorial, I want to go through a quick setup of Composer and ProcessWire that keeps the dependencies, all custom-written code and other source material outside of the webroot, and makes full usage of the Composer autoloader. This setup is pretty basic, so this tutorial is probably more useful to beginners (this is why I'll also include some general information on Composer), but hopefully everyone can take something away from this for their personal workflow.
      Site structure after setup
      This is what the directory structure can look like after the setup:
      . ├── composer.json ├── composer.lock ├── node_modules │   └── ... ├── public │   ├── index.php │   ├── site │   ├── wire │   └── ... ├── packacke-lock.json ├── package.json ├── sass │   ├── main.scss │   ├── _variables.scss │   └── ... ├── src │   ├── ContentBag.php │   └── ... └── vendor ├── autoload.php ├── composer ├── league ├── symfony └── ... As mentioned, the main point of this setup is to keep all external libraries, all other custom source code and resources out of the webroot. That includes Composer's vendor folder, your node_modules and JavaScript source folder if you are compiling JavaScript with webpack or something similar and including external scripts via NPM, or your CSS preprocessor files if you are using SASS or LESS. In this setup, the public directory acts as the webroot (the directory that is used as the entry point by the server, DocumentRoot in the Apache configuration). So all other files and directories in the mysite folder aren't accessible over the web, even if something goes wrong.
      One caveat of this setup is that it's not possible to install ProcessWire modules through Composer using the PW Module Installer (see Blogpost above), but that's just a minor inconvenience in my experience.
      Installation
      You'll need to have composer installed on your system for this. Installation guides can be found on getcomposer.org.
      First, open up your shell and navigate to the mysite folder.
      $ cd /path/to/mysite/ Now, we'll initialize a new Composer project:
      $ composer init The CLI will ask some questions about your projects. Some hints if you are unsure how to answer the prompts:
      Package names are in the format <vendor>/<project>, where vendor is your developer handle. I use my Github account, so I'll put moritzlost/mysite (all lowercase). Project type is project if you are creating a website. Author should be in the format Name <email>. Minimum Stability: I prefer stable, this way you only get stable versions of dependencies. License will be proprietary unless you plan on sharing your code under a FOSS license. Answer no to the interactive dependencies prompts. This creates the composer.json file, which will be used to keep track of your dependencies. For now, you only need to run the composer install command to initialize the vendor directory and the autoloader:
      $ composer install Now it's time to download and install ProcessWire into the public directory:
      $ git clone https://github.com/processwire/processwire public If you don't use git, you can also download ProcessWire manually. I like to clean up the directory after that:
      $ cd public $ rm -r .git .gitattributes .gitignore CONTRIBUTING.md LICENSE.TXT README.md Now, setup your development server to point to the /path/to/mysite/public/ directory (mind the public/ at the end!) and install ProcessWire normally.
      Including & using the autoloader
      With ProcessWire installed, we need to include the composer autoloader. If you check ProcessWire's index.php file, you'll see that it tries to include the autoloader if present. However, this assumes the vendor folder is inside the webroot, so it won't work in our case.
      One good place to include the autoloader is using a site hook file. We need the autoloader as early as possible, so we'll use init.php:
      EDIT: As @horst pointed out, it's much better to put this code inside the config.php file instead, as the autoloader will be included much earlier:
      // public/site/config.php <?php namespace Processwire; require '../../vendor/autoload.php'; The following also doesn't apply when including the autoloader in the config-file.
      This has one caveat: Since this file is executed by ProcessWire after all modules had their init methods called, the autoloader will not be available in those. I haven't come across a case where I needed it this early so far; however, if you really need to include the autoloader earlier than that, you could just edit the lines in the index.php file linked above to include the correct autoloader path. In this case, make sure not to overwrite this when you update the core!
      Now we can finally include external libraries and use them in our code without hassle! I'll give you an example. For one project, I needed to parse URLs and check some properties of the path, host et c. I could use parse_url, however that has a couple of downsides (specifically, it doesn't throw exceptions, but just fails silently). Since I didn't want to write a huge error-prone regex myself, I looked for a package that would help me out. I decided to use this URI parser, since it's included in the PHP League directory, which generally stands for high quality.
      First, install the dependency (from the project root, the folder your composer.json file lives in):
      $ composer require league/uri-parser This will download the package into your vendor directory and refresh the autoloader.
      Now you can just use the package in your own code, and composer will autoload the required class files:
      // public/site/templates/basic-page.php <?php namespace Processwire; use \League\Uri\Parser; // ... if ($url = $page->get('url')) { $parser = new Parser(); $parsed_url = $parser->parse($url); // do stuff with $parsed_url ... } Wiring up custom classes and code
      Another topic that I find really useful but often gets overlooked in Composer tutorials is the ability to wire up your own namespace to a folder. So if you want to write some object-oriented code outside of your template files, this gives you an easy way to autoload those using Composer as well. If you look at the tree above, you'll see there's a src/ directory inside the project root, and a ContentBag.php file inside. I want to connect classes in this directory with a custom namespace to be able to have them autoloaded when I use them in my templates.
      To do this, you need to edit your composer.json file:
      { "name": "moritzlost/mysite", "type": "project", "license": "proprietary", "authors": [ { "name": "Moritz L'Hoest", "email": "info@herebedragons.world" } ], "minimum-stability": "stable", "require": {}, "autoload": { "psr-4": { "MoritzLost\\MySite\\": "src/" } } } Most of this stuff was added during initialization, for now take note of the autoload information. The syntax is a bit tricky, since you have to escape the namespace seperator (backslash) with another backslash (see the documentation for more information). Also note the PSR-4 key, since that's the standard I use to namespace my classes.
      The line "MoritzLost\\MySite\\": "src/" tells Composer to look for classes under the namespace \MoritzLost\MySite\ in the src/ directory in my project root. After adding the autoload information, you have to tell composer to refresh the autoloader information:
      $ composer dump-autoload Now I'm ready to use my classes in my templates. So, if I have this file:
      // src/ContentBag.php <?php namespace MoritzLost\MySite; class ContentBag { // class stuff } I can now use the ContentBag class freely in my templates without having to include those files manually:
      // public/site/templates/home.php <?php namespace Processwire; use MoritzLost\MySite\ContentBag; $contentbag = new ContentBag(); // do stuff with contentbag ... Awesome!
      By the way, in PSR-4, sub-namespaces correspond to folders, so I can put the class MoritzLost\MySite\Stuff\SomeStuff in src/Stuff/SomeStuff.php and it will get autoloaded as well. If you have a lot of classes, you can group them this way.
      Conclusion
      With this setup, you are following secure practices and have much flexibility over what you want to include in your project. For example, you can just as well initialize a JavaScript project by typing npm init in the project root. You can also start tracking the source code of your project inside your src/ directory independently of the ProcessWire installation. All in all, you have good seperation of concerns between ProcessWire, external dependencies, your templates and your OOP-code, as well as another level of security should your Server or CGI-handler ever go AWOL. You can also build upon this approach. For example, it's good practice to keep credentials for your database outside the webroot. So you could modify the public/site/config.php file to include a config or .env file in your project root and read the database credentials from there.
      Anyway, that's the setup I came up with. I'm sure it's not perfect yet; also this tutorial is probably missing some information or isn't detailed enough in some areas depending on your level of experience. Feel free to ask for clarification, and to point out the things I got wrong. I like to learn as well 🙂
      Thanks for making it all the way to the bottom. Cheers!
    • By Marcel
      Hey, 
      - we made a page as admins
      - as admins each  <img> tag is loaded and images are displayed
      - we tested the page as a pre-definded test user which is "guest" (Admin Theme: Reno)
      - as test user each <img> is missing and so no image is displayed
      I checked this in dev-mode on firefox and chrome. Does anyone have an idea or has had similar issues?
       
      Thank you in advance.
       
      Marcel
    • By Guy Incognito
      Hi all. We've created a private log-in area for a client on their site that is restricted on a roles basis. Is there a simple solution available to let them upload files to a file field and then choose individual users that can access individual files?
      Does that make sense?!... it's hard to search for answers to this as all results pertain to server file permissions.
       
    • By Jennifer Stock
      Greetings. I would like to restrict access to certain sections of my organization's ProcessWire site using pubcookie. We are rolling out Shibboleth authentication later this year but for now, it seems I can only make use of our institution's single sign-on routine by utilizing rules in an .htaccess file. 
      I am wondering if there is a way to ask PW to apply these rules to certain pages in the site, whether via template type or location in the page tree:
      AuthType UWNetID PubcookieAppID "MyApplication" require type staff faculty  
    • By anttila
      We are developing an App that sends data over the Internet to ProcessWire (POST/JSON). We want password to be protected somehow when sending it, but I should be able to compare it to PW's passwords. We were thinking of using md5 encryption, but PW uses different encryption.
      How can I be sure that user has active account when they use the App?