Pages

Tuesday 31 December 2013

Mobile for Drupal 8

In my State of Drupal keynote in Chicago I said: "If I were to start Drupal from scratch today, I'd build it for mobile experiences first, and desktop experience second.". I believe in that more than ever.
We already have a number of initiatives under way that will make Drupal a great platform for building native mobile applications (e.g. the Web services initiative) as well for building mobile web experiences (e.g. the HTML5 initiative and theDesign initiative).
However, there is more that needs to be done to make Drupal a go to platform in a mobile world. For example, a couple of weeks ago I talked to a number of big media companies, each employing hundreds of editorial staff. They all believed that in less than two years, most of their editors that report from the field will be using tablets instead of laptops. Applied to Drupal, this means we need to make the Drupal administration back-end and the editorial experience mobile-friendly, something that isn't covered by the existing Drupal 8 initiatives. Another example would be responsive web design.
The mobile internet is coming at us fast and furious. We need to move fast and we might only get one shot at this. I want to make mobile the big theme for Drupal 8. That is why I decided to launch another initiative related to mobile.
I've asked John Albin Wilkins to be the Initiative Owner for the Drupal 8 Mobile Initiative, and to work with the existing initiatives to fill the remaining gaps. To learn what that means, please consult John's announcement blog post, which includes an overview of the initiatives' goals. Like with any of these initiatives, they don't actually materialize unless people decide to help. To get involved, please join the discussions in the Mobile group on groups.drupal.org and help work on Mobile issues on drupal.org.

HTML5 in Drupal 8

HTML5 is about to rock our world. There are books written about why that is the case, but simply put, it can provide a much better user experience on both desktop and mobile devices, and could lead to a convergence between native applications and the mobile web.
I believe in HTML5 enough that I wanted to make it one of the top 5 initiatives for Drupal 8; and switch Drupal's default doctype from XHTML to HTML5. This is the fifth official Drupal 8 initiative after the Configuration ManagementDesignWeb Services and Multilingual initiatives.
I have asked Jacine Luisi to be the Initiative Owner for the Drupal 8 HTML5 Initiative. Jacine is a prolific themer and contributor known to be a markup/CSS nut. I'd also like to recognize Jen Simmons for all her evangelism work on HTML5 in Drupal. I hope that work continues as it can feed into the HTML5 Core Initiative.
The way we'll approach this initiative is by starting off with some of the low-hanging fruit, and gradually work our way up to more advanced parts of the specification. In her announcement blog post, Jacine provides a plan for what that means.
To keep track of what is going on, tune into the core issue queue on issues tagged HTML5 or participate in the HTML5 group. Details will be posted shortly on the core initiative homepage.

Drupal in a tablet world

Ipad ad
A few years ago, computer tablets similar to Apple's iPad were props in science fiction films. Only a couple of years from now, tablets might be among the most popular consumer electronics ever.
It took less than three months to sell the first 3 million iPads. This has made the iPad the consumer electronics device with the fastest adoption rate of all time. Compare that with the 1 million iPhones sold in the first three months of its release, and the 350,000 DVD players sold in the first year of their mass production.
According to CNBC, the iPad will surpass gaming equipment and the cellular phone to become the fourth most popular consumer electronics category -- televisions, smart phones, and notebook computers are the top three. Large companies like Hewlett Packard have no choice but to design credible alternatives to the iPad. Samsung will soon begin to distribute their Galaxy Tab, which runs on Android OS, in Europe and the U.S. Once these big players enter the market fully, it's pretty clear that we're heading to a new lifestyle in which everyone and his dog owns a tablet. I already have mine.
This all begs the question: in a world of tablets and mobile handheld devices, what do we need to do so that Drupal will be a go-to platform? How can Drupal contribute so as to be a player in the ever-expanding ecosystem of tablets and mobile phones? What needs to change so that developers can build easily tablet and mobile phone optimized applications on top of Drupal? At the rate that tablets and mobile devices are being adopted, we don't have much time to get in motion. Drupal 7 takes enormous steps in the right direction, and I have a some ideas for Drupal 8. However, I'd like to get your take first ...
Thoughts?

Spark update: mobile administration in Drupal

Today, I'd like to share an HTML/JS prototype we've created for a mobile toolbar and dashboard for Drupal that we hope to include as part of the Spark distribution and then propose for Drupal 8 core as part of the Drupal 8 Mobile Initiaitve.
Drupal 7's default administration tools (e.g. Toolbar module and Shortcut module) were not designed in a “mobile first" way, and as such can be difficult to work with on tablets or smartphones. For example, here is a screenshot of what happens to the Toolbar and Shortcut modules when using a responsive version of the Bartik theme on an iPhone:
Drupal toolbar on iphone
On an iPhone or other mobile device, the default Drupal 7 toolbar and shortcut bars both wrap, taking up nearly a third of the screen.
Kevin O'Leary from the Spark team has come up with the following design. The toolbar design in particular takes heavy inspiration from efforts by Lewis Nymanand his mobile navigation prototype.
We set out to do justice to the complexites of Drupal's administration layer while accounting for the constantly evolving universe of devices. We think what we've come up with is scalable, responsive, and usable.
Here is Preston So, author of the prototype, demonstrating the functionality in a short, 7 minute video:

As we begin work on this feature, it will live at the Mobile friendly navigation toolbar project as a contributed module for Drupal 7 first. If these changes are well-received, I hope we can target this functionality for Drupal 8 core, as a replacement for the Toolbar and Shortcut modules.

Monday 30 December 2013

Spark update: in-line editing in Drupal

The goal of the Spark distribution is to incubate authoring experience improvements in a Drupal 7 and Drupal 8. It was announced earlier this month, and since then we've been hard at work on initial research and design.
The Spark team's primary focus is on improving Drupal's content authoring and editing experience, and the first feature we're prioritizing is in-place editing: the ability to edit content, menus, etc. directly on the page, without the need to navigate to a separate edit form. Think of it as "true" WYSIWYG.
Members of Acquia's design team spent time analyzing how some of the most widely adopted Open Source as well as proprietary CMSs do in-place editing. We then prototyped some initial ideas, and performed usability testing on those prototypes to see what works and what doesn't. After a number of iterations, we're happy to report that the usability testing has validated Spark's general design direction. People loved the prototype. Now is a good time for us to share our initial prototype and to solicit further feedback from the community so we can shift gears into implementation.
The following 5-minute video walks through the HTML/JS prototype, and also provides a bit of background on the Spark project:


Our goal is to deliver this functionality in a contributed module for Drupal 7 first and foremost, which will live at the In-Place Editing project on drupal.org. This module will be bundled into the Spark distribution. Depending on how it is received, I hope we can also target this functionality for Drupal 8 core.
From a technical architecture standpoint, we are currently in the process ofselecting the WYSIWYG editor to use in Spark for in-place editing of HTML content. For now, we plan to focus on supporting only the Filtered/Full HTML text formats in order to get us to something testable faster.
Later, we are hoping to branch out into other areas of authoring experience too, including helping with the content creation form improvements that the Drupal usability team has been spear-heading, as are well as the layouts UI work being actively discussed in the usability group. The Drupal usability team is doing an incredible job with these issues, and once fully staffed, I would like to see the Spark team help implement these improvements for Drupal 8 and backport them to Drupal 7 so we can ship it with the Spark distribution. (Did I mention that the Spark team is hiring? ;-))
As you can see, things are starting to move along quite nicely. Please join the discussion in the Spark issue queue if this functionality sounds exciting to you and you'd like to help!

Announcing Spark: authoring improvements for Drupal 7 and Drupal 8

At DrupalCon Denver, I announced the need for a strong focus on Drupal's authoring experience in my State of Drupal presentation. During my core conversation later in the week, I announced the creation of a Drupal 7 distribution named "Spark" (formerly code-named "Phoenix"). The goal of Spark is to act as an incubator for Drupal 8 authoring experience improvements that can be tested in the field.
I hope for Spark to provide a "safe space" to prototype cutting-edge interface design and to build excellent content tools that are comparable with the experience of proprietary alternatives. While not a final list, some initial thinking around the features we want to experiment with is:
  • Inline editing and drag-and-drop content layout tools ("true" WYSIWYG)
  • Enhanced content creation: auto-save, save as draft and more
  • Useful dashboards for content creators
  • Mobile content authoring and administration support
The vision behind the Spark distribution is to be "the Pressflow of Drupal authoring experience". Pressflow provided a "spoon" of Drupal 6 with various performance enhancements that made their way into Drupal 7 core while it was in development. The same improvements were made available to Drupal 6 users so they could easily be tested in the field. With Spark, we want to test authoring experience improvements in Drupal 7 on real sites with real users and real content. We also want to target the best improvements for inclusion into Drupal 8 core.
I'm excited to announce that Acquia will fund the Spark distribution. Core developers Gábor Hojtsy and Wim Leers will work on Spark full-time starting in late May. They will work along side Angie Byron (webhchick), Alex Bronstein(effulgentsia), myself and other members at Acquia. While we have some promising candidates so far, Acquia is still seeking applicants to join the Spark team (with a strong preference to candidates located in or willing to move to the Boston area):
The Spark team will collaborate with the Drupal usability and the core development teams.

Spark update: WYSIWYG editing for Drupal

After a lot of discussion and testing, we decided to adopt the Aloha Editor as the WYSIWYG editor for Spark, and possibly for Drupal 8 core. Check out Wim's blog for the details. In short, it is the best HTML5 based WYSIWYG editor; fast, well-written and future-proof.
Here is a screenshot of our latest designs of how we envision integrating the Aloha Editor in Spark on a mobile device:
Aloha editor for Spark on a mobile device
By tapping into a rich text field such as Body, a toolbar comes up with two tabs with editor buttons below: Format (containing buttons such as Bold, Italic, Left/Right Align, and Lists) and Insert (for Links, Images, and the like).
I also wanted to give a big thank you to Haymo Meran, creator of Aloha Editor and Director of Product Experience at Gentics Software GmbH, both for hosting a Drupal/Aloha collaboration sprint at his company's offices in Vienna last month, and also for changing the license of Aloha Editor to GPLv2+ (from AGPLv3) so that it could be used with Drupal!
It's an incredible gift to the Drupal project and the Open Source community at large. Thanks!

Spark update: ready for alpha testing

The Spark distribution is a Drupal 7 distribution which aims to prototype cutting-edge authoring experience improvements that we hope to propose for inclusion in Drupal 8 core. Since we announced Spark back in May, we've shown videos of prototypes of inline editingresponsive layout building and mobile administration. The rest of the Spark team (Angela Byron, Kevin O'Leary, Wim Leers, Gábor Hojtsy, Jesse Beach, Preston So and Dharmesh Mistry) has also been working hard to make these designs a reality.
There has been a lot of great progress over the past months, and with the release of Spark 7.x-1.0-alpha4, Spark is now ready for some community testing! Each module/theme that Spark builds upon is a separate, standalone contributed project that can be integrated into existing sites. This alpha release includes:
  • Inline Editing, courtesy of Edit module. You can click into a node, switch the “View / Edit" toggle in the toolbar, and then click directly into any field to edit its contents, instead of having to be redirected to the backend.
  • True WYSIWYG, courtesy of Aloha Editor. Edit your rich text with your theme's direct styling through the inline editor. It even works with images + captions, links directly to content in the site, and has basic support for tokenized strings.
  • Responsive Layout Builder, courtesy of the Layout and Gridbuildermodules. You can configure layouts for separate breakpoints (e.g. Mobile, Tablet, Desktop) and even define your own grids for them to snap to. These technologies layer on top of Panels,though it's been architected so it could be integrated with other layout solutions as well.
  • New admin theme, brought to you by Ember. This brings some nice light styling on Drupal core's Seven admin theme as well integrating theAdmin module to better support mobile devices. A more fleshed out mobile toolbar and administrative experience is slated for implementation soon.
If you'd like to try the distribution out without downloading and installing it, check our demo site at http://demo.sparkdrupal.com. (Note that since this site is open to anyone, it might look a bit funny at any given time. If things are really broken, please check back later.)
There is still much to do, but hopefully this release will provide a good understanding of the direction Spark is taking, and what we hope to propose for inclusion in Drupal 8 core. We greatly welcome feedback, bug reports and patches in the Spark issue queue.
At DrupalCon Munich next week, we'd love to talk more about how we can move some of these things into Drupal 8 core. We've setup various Spark sessions and BoFs at DrupalCon Munich to plan and brainstorm about this.

Node.js integration to Drupal

Node.js integration
===================
This module adds Node.js integration to Drupal.
Setup
=====
1. Install Node.js.

 Installing Node.js and NPM on Ubuntu/Debian

How to Install Node.js

2. Install required Node.js modules with the Node Package Manager (NPM).
Make sure you are in the nodejs module directory - NPM needs the package.json
file that comes with the nodejs module to install the right modules.
cd path/to/your/nodejs/module/directory
npm install
npm uninstall express
npm install express@2.5.9
3. Create a 'nodejs.config.js' file in your nodejs module directory.
Read the 'nodejs.config.js.example' file. A basic configuration can be as simple as:
/**
* This configuration file was built using the 'Node.js server configuration builder'.
* For a more fully commented example see the file nodejs.config.js.example in the root of this module
*/
backendSettings = {
"scheme":"http",
"host":"192.168.1.61",
"port":8080,
"key":"/path/to/key/file",
"cert":"/path/to/cert/file",
"resource":"/socket.io",
"publishUrl":"publish",
"serviceKey":"",
"backend":{
"port":80,
"host":"localhost",
"messagePath":"/drupal7/nodejs/message/"},
"clientsCanWriteToChannels":false,
"clientsCanWriteToClients":false,
"extensions":"",
"debug":true,
"transports":["websocket",
"flashsocket",
"htmlfile",
"xhr-polling",
"jsonp-polling"],
"jsMinification":true,
"jsEtag":true,
"logLevel":1};
Set debug to false when you are happy with your setup.
4. Run the node server with the command: node server.js
As long as you have 'debug: true' in your configuration file, you'll see lots of helpful messages.

Installing Node.js and NPM on Ubuntu/Debian

This is just short snippet on how to install Node.js (any version) and NPM (Node Package Manager) on your Ubuntu/Debian system.
Step 1 - Update your system
sudo apt-get update
sudo apt-get install git-core curl build-essential openssl libssl-dev
Step 2 - Install Node.js
First, clone the Node.js repository:
git clone https://github.com/joyent/node.git
cd node
Now, if you require a specific version of Node:
git tag # Gives you a list of released versions
git checkout v0.4.12
Then compile and install Node like this:
./configure
make
sudo make install
Then, check if node was installed correctly:
node -v
Step 3 - Install NPM
Simply run the NPM install script:
curl http://npmjs.org/install.sh | sudo sh
And then check it works:
npm -v
That's all.

How to Install Node.js Essay Steps

This was the first in a series of posts leading up to Node.js Knockout on how to use node.js.
I have been given permission to repost the articles from the contest here (in wheat format) for general consumption. Expect more to come.
In this post we detail how to install node on MacUbuntu, and Windows.

Mac

If you're using the excellent homebrew package manager, you can install node with one command: brew install node.
Otherwise, follow the below steps:
  1. Install Xcode.
  2. Install git.
  3. Run the following commands:
darwin_setup.sh
git clone git://github.com/ry/node.git cd node ./configure make sudo make install
You can check it worked with a simple Hello, World! example.

Ubuntu

  1. Install the dependencies:
    • sudo apt-get install g++ curl libssl-dev apache2-utils
    • sudo apt-get install git-core
  2. Run the following commands:
ubuntu_setup.sh
git clone git://github.com/ry/node.git cd node ./configure make sudo make install
 Step 3 - Install NPM
Simply run the NPM install script:
curl http://npmjs.org/install.sh | sudo sh
And then check it works:
npm -v
You can check it worked with a simple Hello, World! example.
Thanks to code-diesel for the Ubuntu dependencies.

Windows

Currently, you must use cygwin to install node. To do so, follow these steps:
  1. Install cygwin.
  2. Use setup.exein the cygwin folder to install the following packages:
    • devel → openssl
    • devel → g++-gcc
    • devel → make
    • python → python
    • devel → git
  3. Open the cygwin command line with Start > Cygwin > Cygwin Bash Shell.
  4. Run the below commands to download and build node.
cygwin_setup.sh
git clone git://github.com/ry/node.git cd node ./configure make sudo make install
For more details, including information on troubleshooting, please see the GitHub wiki page.

Hello Node.js!

Here's a quick program to make sure everything is up and running correctly:
hello_node.js
var http = require('http'); http.createServer(function (req, res) {   res.writeHead(200, {'Content-Type': 'text/plain'});   res.end('Hello Node.js\n'); }).listen(8124, "127.0.0.1"); console.log('Server running at http://127.0.0.1:8124/');
Run the code with the node command line utility:
> node hello_node.js Server running at http://127.0.0.1:8124/ 
Now, if you navigate to http://127.0.0.1:8124/ in your browser, you should see a nice message.

Congrats!

You've installed node.js.

8 Practical PHP Regular Expressions

Validating a Username:
Quote: Something often overlooked, but simple to do with a regular expression would be username validation. For example, we may want our usernames to be between 4 and 28 characters in length, alpha-numeric, and allow underscores. PHP Code: $string = "userNaME4234432_";
if (preg_match('/^[a-z\d_]{4,28}$/i', $string)) {
echo "example 1 successful.";
}
Telephone Numbers:
Quote: Number in the following form: (###) ###-#### PHP Code: $string = "(232) 555-5555";
if (preg_match('/^(\(?[0-9]{3,3}\)?|[0-9]{3,3}[-. ]?)[ ][0-9]{3,3}[-. ]?[0-9]{4,4}$/', $string)) {
echo "example 2 successful.";
}
Emails:
PHP Code: $string = "first.last@domain.co.uk";
if (preg_match(
'/^[^0-9][a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)*[@][a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)*[.][a-zA-Z]{2,4}$/',
$string)) {
echo "example 3 successful.";
}
Postal Codes:
PHP Code: $string = "55324-4324";
if (preg_match('/^[0-9]{5,5}([- ]?[0-9]{4,4})?$/', $string)) {
echo "example 4 successful.";
}
Ip Address:
PHP Code: $string = "255.255.255.0";
if (preg_match(
'^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:[.](?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$',
$string)) {
echo "example 5 successful.";
}
Hexadecimal Colors:
PHP Code: $string = "#666666";
if (preg_match('/^#(?:(?:[a-f\d]{3}){1,2})$/i', $string)) {
echo "example 6 successful.";
}
Multi-line Comments:
PHP Code: $string = "/* commmmment */";
if (preg_match('/^[(/*)+.+(*/)]$/', $string)) {
echo "example 7 successful.";
}
Dates:
Quote: MM/DD/YYYY format PHP Code: $string = "10/15/2007";
if (preg_match('/^\d{1,2}\/\d{1,2}\/\d{4}$/', $string)) {
echo "example 8 successful.";
}
Some might be more/less useful than the others but that will depend on the project you are working on.

Cropping Images using PHP

This script will allow you to make a smaller image of a bigger image, but at the same time crop it. This will prevent the image looking stretched and deformed.
We will create this using a class (Sorry using PHP 4 at the moment, but should work on 5)
Firstly lets set up the class.
PHP Code: class cropImage{
//code here
}
Now we need to set up some variables to be used throughout the program.
PHP Code: var $imgSrc,$myImage,$cropHeight,$cropWidth,$x,$y,$thumb;
The variables above will be explained once we use them. Now we need to create the first function. This function will get the image we are going to crop, work out its dimension and then use them dimensions to work out how we are going to crop it.
PHP Code:
function setImage($image)
{
//Your Image
$this->imgSrc = $image;
//getting the image dimensions
list($width, $height) = getimagesize($this->imgSrc);
//create image from the jpeg
this->myImage = imagecreatefromjpeg($this->imgSrc) or die("Error: Cannot find image!");
if($width > $height) $biggestSide = $width; //find biggest length
else $biggestSide = $height;
//The crop size will be half that of the largest side
$cropPercent = .5; // This will zoom in to 50% zoom (crop)
$this->cropWidth   = $biggestSide*$cropPercent;
$this->cropHeight  = $biggestSide*$cropPercent;
//getting the top left coordinate
$this->x = ($width-$this->cropWidth)/2;
$this->y = ($height-$this->cropHeight)/2;
}
Now we actually need to start creating the actual cropped image.
PHP Code: function createThumb()
{
$thumbSize = 250; // will create a 250 x 250 thumb
$this->thumb = imagecreatetruecolor($thumbSize, $thumbSize);
imagecopyresampled($this->thumb, $this->myImage, 0, 0,$this->x, $this->y, $thumbSize, $thumbSize, $this->cropWidth, $this->cropHeight);
}
Now all we need to do is render the image out.
PHP Code: function renderImage()
{
header('Content-type: image/jpeg');
imagejpeg($this->thumb);
imagedestroy($this->thumb);
}
Now we just need to create the instance
PHP Code: $image = new cropImage;
$image->setImage($src);
$image->createThumb();
$image->renderImage();
You can use this script to display a thumb of images on a new page, by using the following page.
PHP Code: <img src="thumbcreate.php?src=images/largimg.jpg"> //link to large image

Test Credit Card Account Numbers

While testing, use only the credit card numbers listed here. Other numbers produce an error.
Expiration Date must be a valid date in the future (use the mmyy format).

Test Credit Card Account Numbers

Credit Card TypeCredit Card Number
American Express378282246310005
American Express371449635398431
American Express Corporate378734493671000
Australian BankCard5610591081018250
Diners Club30569309025904
Diners Club38520000023237
Discover6011111111111117
Discover6011000990139424
JCB3530111333300000
JCB3566002020360505
MasterCard5555555555554444
MasterCard5105105105105100
Visa4111111111111111
Visa4012888888881881
Visa4222222222222
Note : Even though this number has a different character count than the other test numbers, it is the correct and functional number.
Processor-specific Cards
Dankort (PBS)76009244561
Dankort (PBS)5019717010103742
Switch/Solo (Paymentech)6331101999990016

Securing PHP Files using HTTP Authentication

IntroductionIt is quite common to have the need to password protect a certain file or a set of files, in order to prevent unauthorized access to those files. There are many different alternatives on how to do this including, sessions, cookies, JavaScript and HTTP authentication. The latter of these is what we are going to concentrate on in this article.
Usually this form of authentication is called Apache HTTP Authentication as it is only available for Apache based web server. To be honest, that is a lie as it is also possible with Microsoft's IIS web server, however, is much more difficult to implement and requires many configuration changes in order for it to run successfully. Hence, we will only focus on getting this working under Apache.
Apache
For those of you who don't know what Apache is, it is a web server. Therefore, it is the 'program' that is running PHP and that accepts incoming requests for web pages and sends out the correct data. As we are focusing on Apache in this article, it is important to know if you are running Apache or not. This is fairly simple to find out, using thephpinfo() function. Simple create a PHP page with the following code:
phpinfo();
?>
Run this new file and you should get an output which contains a lot of information about your current PHP setup. The most important section is the top section, and should look something like the following:
Look at the Server API field and make sure that it says Apache. If it does, then you are running the perfect configuration – Apache with PHP as a module. The field may say CGI, if it does, you will have to scroll down the page, and check if there is an 'Apache' section. If there isn't, it is likely that you aren't running Apache, hence this article probably won't be of much use. If you want, you can always install Apache on your PC by checking out this auto-installer.
If you are running Apache and CGI-mode, then there is a slight chance that the code supplied will not work, however, I have modified it so that your chances are quite high. By default though, HTTP Authentication doesn't work in CGI mode, however with a small trick it can be made to work.
What is HTTP Authentication?
You may not consciously know what HTTP Authentication is; however, it is most likely that you have used it once or twice, if not many of times. It is used commonly as login interfaces to the administration areas of some PHP scripts, as well as some popular websites, such as vBulletin.com. To refresh your memory, here is a small image of the login process:
Now that you know what HTTP Authentication is, it's time to find out how to implement it for single and multiple files.
Protecting Single and Multiple FilesWe are going to start off adding password protection to a single file, and then modify that so we add it to multiple files. The way HTTP authentication works, is by using HTTP headers which the browser and the web server (Apache) both understand. By using the correct headers we can produce a page which asks for the user to login. If the entered information is correct, we show the page, otherwise we show a nice error message.
As I mentioned, the basis of HTTP authentication is using HTTP headers, which are accessible by using the PHPheader() function. This specifics of this function have been explained before in great detail in Speed Limit File Downloads. However, for the sake of drilling it into your brains, the most important thing about the header() function is that there can be no output to the browser before calling header(). If there is, you will receive a nasty error and the script will cease to function.
Here's the code:
HTTP Authenticationif (@$_SERVER['PHP_AUTH_USER'] != 'john' && @$_SERVER['PHP_AUTH_PW'] != 'secret') {
header('WWW-Authenticate: Basic realm="Site Administration Area"');
header('Status: 401 Unauthorized');
/* Special Header for CGI mode */
header('HTTP-Status: 401 Unauthorized');
?>
Access Unauthorized
Access to the requested page denied
You have been denied access to this page for entering an
incorrect or non-exist username and password.
Press 'Refresh' to retry the login procedure.
exit;
}
echo 'Welcome to our site, username ' . $_SERVER['PHP_AUTH_USER'];
?>
This code contains all the important aspects of HTTP authentication that you need to get started. First thing to notice is that there is no output before header() calls. Secondly, notice that we have two special variables inside the$_SERVER superglobal. These are PHP_AUTH_USER and PHP_AUTH_PW and they represent the current HTTP authenticated username and password. As they may not exist when we call our script, I have placed an 'at' symbol (@) before both of these variables. The @ symbol tells PHP to suppress any errors that may arise in the specified statement. Hence, we know that an error might occur because these variables may not yet exist, so we use @ to suppress it.
The way the headers are written are very important using this method of authentication, as very slight changes can result in the login procedure not working and everyone having access to your file(s). It is important that the orders of the headers are correct and that the actual content is correct. For example, for maximum compatibility, the B in Basicmust be capital, as well as the text in realm being surrounded in double quotes, not single.
In the first header, we have a realm option. This is where we can place some text that will go on our username / password request form. You shouldn't place too much text here, just a basic description of what the user is logging in to.
The usage of this script is a little strange to visualize, because first we check if the user is logged in, and if not, then we send some headers and then end the script. If actual usage, after the headers are sent, the browser waits from the input from the user. Once the user clicks on the OK button, it will then reload the script, to check if the username and password combination are correct. If not it will display the login again (up to three times), and then upon failure will show the error page. If the username is correct, it skips the headers section, and just displays the normal content of your script.
Securing Multiple Files
Most of the time when you are password protecting an area on your website, you will need to secure more than one page. What you would then do, if move all the above code into an include file, and then include the file on any page that you want to password protect. This could become cumbersome, especially if you are already including many files. The alternative is to convert this into a function, so that you can add it into a function library file (which you might already have). This way, the code is always available, and we can make it a little more reuseable.
Reusable Codefunction validateUser ($fUsername = 'john', $fPassword = 'secret') {
if (@$_SERVER['PHP_AUTH_USER'] != $fUsername && @$_SERVER['PHP_AUTH_PW'] != $fPassword) {
header('WWW-Authenticate: Basic realm="Site Administration Area"');
header('Status: 401 Unauthorized');
/* Special Header for CGI mode */
header('HTTP-Status: 401 Unauthorized');
?>
Access Unauthorized
Access to the requested page denied
You have been denied access to this page for entering an
incorrect or non-exist username and password.
Press 'Refresh' to retry the login procedure.
exit;
}
}
?>
Now we have a function called validateUser which takes two parameters; $fUsername and $fPassword. These are the username and password that you want the user to login with. I have also added default values so that if you do not specify a username or password (maybe you forget to), then the user can log in with the default values.
This function can then be added to a library file of functions. These are used to hold commonly used functions in your programs and are usually necessary if you are writing a lot of scripts. Commonly, I use global.php for my library functions.
index.phprequire_once('globa.php');
validateUser('john', 'newsecret');
echo 'Welcome to our secret area!';
?>
Here I have assumed that you have placed the function into a file called globa.php so that we can include it. I have used require_once() to include the file, so that if PHP cannot find the file, the script will exit and also the file will not be included more than once. Now to run the authentication routine, we just make a simple call to validateUser() with the username and password we expect the user to log in with.
These examples are useful if you only have one or two people logging into your site and they share the same username. However, sometimes you may want to allow a multitude of people to access this area. For this, it is common to use databases.
Allowing Multiple UsersThere are two main methods of allowing multiple users password protected access to your website. The first being username/password files and the second being username/password tables in a database. As many people use database nowadays, I will now focus on this method. In order to implement a file based version of this script, you will have to save usernames and passwords to a file (username,password on each line). You would then read each line, and check if the username and password match.
Back to the main topic of databases! They are useful in this sense, and often websites have a dynamic Content Management System (CMS) for their website which has allows for several users or authors to access this area. The author data is already stored in the database, so there is no need to add a file or more data. I'm going to assume you know a little about how to access MySQL databases in this section, but don't worry, it should be too difficult.
To start of with, we need a table of the usernames and passwords. This is SQL which can be executed by running MySQL via the command line, or by using a script such as phpMyAdmin.
CREATE TABLE 'users' (
'userID' INT NOT NULL AUTO_INCREMENT,
'username' VARCHAR( 20 ) NOT NULL ,
'password' VARCHAR( 20 ) NOT NULL ,
PRIMARY KEY ( 'userID' ) ,
UNIQUE ( 'username')
);
Now, let's enter a few users:
INSERT INTO 'users' ( 'userID' , 'username' , 'password' )
VALUES ( '', 'john, 'secret');
INSERT INTO 'users' ( 'userID' , 'username' , 'password' )
VALUES ( '', 'peter', 'othersecret');
INSERT INTO 'users' ( 'userID' , 'username' , 'password' )
VALUES ( '', 'billy', 'ilovecats');
Now we have our database table setup called users. On my computer, I have this table in a database called myCms so we will use that in our examples.
To get going, we must first connect to the database. At the same time, we are also going to convert all this into our own function so that it is again reusable in the future.
Connect
function validateUser () {
mysql_connect('dbusername', 'dbpassword', 'localhost') or die(mysql_error());
mysql_select_db('myCms') or die(mysql_error());
}
?>
Here we have connected to the database using our database name and password. You must change the username and password for your setup. We then select our database (myCms). If any errors occur the script is terminated and the error is outputted using die(mysql_error()). This is especially useful in determining any bugs in your scripts.
Now we must query the database and check if the username and password that has been entered is correct:
function validateUser () {
mysql_connect('dbusername', 'dbpassword', 'localhost') or die(mysql_error());
mysql_select_db('myCms') or die(mysql_error());
$user = @addslashes($_SERVER['PHP_AUTH_USER']);
$password = @addslashes($_SERVER['PHP_AUTH_PW']);
$sql = "SELECT Count(*) as Number FROM users WHERE username='" . $user . "' AND password='" . $password . "'";
$query = mysql_query($sql) or die(mysql_error());
$result = mysql_fetch_array($query);
$NumberOfUsers = $result['Number'];
}
?>
This may be a little daunting but it is simple in essence. All we have done, is modified the input username and password by calling addslashes() on them. This is a security issue and should always be performed on user input to database, to prevent them from gaining unauthorized access.
We then have our query, which selects (gets) numbers of records that meets our conditions. Our conditions state the username and password must match the ones that the user has entered.
Following this, we execute the query, get the results and then assign the result called Number to a variable called$NumberOfUsers so that we can use it. Now all that's left to do, is the standard header output:
Altogether Now
function validateUser () {
mysql_connect('dbusername', 'dbpassword', 'localhost') or die(mysql_error());
mysql_select_db('myCms') or die(mysql_error());
$user = @addslashes($_SERVER['PHP_AUTH_USER']);
$password = @addslashes($_SERVER['PHP_AUTH_PW']);
$sql = "SELECT Count(*) as Number FROM users WHERE username='" . $user . "' AND password='" . $password . "'";
$query = mysql_query($sql) or die(mysql_error());
$result = mysql_fetch_array($query);
$NumberOfUsers = $result['Number'];
if ($NumberOfUsers != 1) {
header('WWW-Authenticate: Basic realm="Site Administration Area"');
header('Status: 401 Unauthorized');
/* Special Header for CGI mode */
header('HTTP-Status: 401 Unauthorized');
?>
Access Unauthorized
Access to the requested page denied
You have been denied access to this page for entering an
incorrect or non-exist username and password.
Press 'Refresh' to retry the login procedure.
exit;
}
}
?>
This is essentially the same as the code of the previous page, however this time, as we have queried the database for the number of users where the username/password match, we do not have to again check the input username/password. Instead, we have the number of users with the correct match – this should equal to 1 or 0, and never more. Hence, we check if the number does not equal to 1, if so, we send the headers.
As we have defined this all in a function, we can again move this into a library file and now we can call this on every page using this method:
Multiple Pages
require_once('global.php');
validateUser();
echo 'Welcome to the secured area!';
?>
This is almost the same as previously, except there are no parameters for the validateUser() function as all the username / password combinations are taken from the database.
I hope this article has helped you gain an understanding on how to password protect your website using this simple but efficient method. You should now try it out for yourself, or maybe consider implementing the file based version.