| By Joshua Drake | Article Rating: |
|
| December 10, 2001 12:00 AM EST | Reads: |
1,906 |
(LinuxWorld) -- My first article on LXP was essentially an introduction, and a basic HOWTO on LXP as a whole. This article will detail the basics of creating an actual application with LXP. However, before we get into that, I would like to introduce you to a particular feature of LXP -- reserved objects.
LXP, like PHP, implicitly creates a global variable in memory for each CGI argument passed to it. Legal characters in a variable's name are any number, any letter, and the underscore. Additionally, LXP can set variable values associated with an LXP "object."
An object represents a collection of variable values, referenced through a common name. A variable within an object can be set and referenced either by a period, or by square brackets following the object name (e.g., myobject.value, or myobject[0]). LXPs argument parser identifies periods and brackets if they are passed to LXP through an HTML GET or POST method. Once the arguments are passed the corresponding objects will be built, with the exception of reserved objects.
A variable value within a reserved object cannot have its value set by CGI arguments because they have a reserved function. For example, in LXP 0.8, we have the lxp (imagine that) object. The lxp object is designed to be protected from external value modification, and is used to maintain reserved values. For example:
<lxp> <putvar name="lxp.version"> </lxp>
The previous example will output a string similar to the following: lxp 0.8.2/Development
Why is this useful? Well, Web sites use variables to configure the way a particular page will be displayed to the user. If you were to go to Google and search for Linux, it would result in 47 million results. Obviously it would be a long night if Google displayed all 47 million results at the same time. Instead, by using variables Google shows you 10 results at a time.
If you look in your location bar after performing the search on Linux at Google you will see something similar to this:http://www.google.com/search?q=linux
If you scroll down and click on the next result set, you will see a URL in the location bar similar to the following:http://www.google.com/search?q=linux&hl=en&start=10&sa=N
Take notice of the "start" CGI argument in the location bar. It has a value of 10. You can change that value at will within the address bar, and Google will return the results as specified (if it is a valid value). For example: http://www.google.com/search?q=linux&hl=en&start=50&sa=N
This is fine for something such as Google (which is only the best search engine on the Web), but what if it were something more important that you didn't want to have changed? You can achieve this by use the lxp object. As an example, I created a file called index.lxp that contains the following:
<lxp><ifnot submit> <form method=post action="/contact/index.lxp"> Username: <input type="text" name="username"> <br /> Password: <input type="password" name="password"> <br /> <input type=submit name=submit value="Submit"> </form> </ifnot>
<if submit="Submit"> <include src="dbname=lxparticle user=postgres" sql="SELECT username, password, rights FROM users WHERE username='$username' AND password='$password'" setvars="lxp"> </include>
<if sql.numrows="1"> <setvar lxp.authenticated="1"> <include src="insert.lxp" /> </if>
<ifnot lxp.numrows="1"> I am sorry <putvar name="username"> you appear to be a ghost. </ifnot> </if> </lxp>
The above LXP file performs the following actions:
- If the submit does not have a value, display an HTML form.
- If the argument "submit" has a value of "Submit," process a SQL query, and set some variables based on the results. The inclusion also sets all selected column variables from the query to the lxp object, which are thus protected.
- If the number of rows returned by the SQL query is 1, then set an variable of "authenticated" within the lxp object to the number 1, and include the insert.lxp file.
- If the number of rows returned is not 1, then inform the user that they do not exist.
This is an overly simplified example, but it will allow us to demonstrate our concept. The markup for the insert.lxp file looks like this:
<lxp><if lxp.authenticated="1"> <if lxp.rights="5"> <h3> Hello <i><putvar name="username"></i> you are currently authenticated and you have a security level of <i><putvar name="lxp.rights"></i>. Thus, you are a super-user. You can destroy the entire system. Please be careful. </h3> </if>
<else> <h3> Hello <putvar name="username"> you are currently authenticated and you have a security level of <putvar name="lxp.rights">. You are an end user. You have only have the ability to enter bad data. </h3> </else> </if>
</lxp>
The markup within the insert.lxp file performs the following:
- If lxp.authenticated (which was set in index.lxp) is equal to the number 1, the user is authenticated, and further checks will be made.
- If the user has a rights level (lxp.rights, set by the SQL inclusion) of 5, explain to the user that they are a super-user.
- If the user does not have a rights level of 5, explain to the user that they are a normal end user.
The above example is simple, but it does illustrate why the lxp object is important. Let's look at the Google example again. In the Google example I explained that by changing one parameter in the location bar, a user could change the results by making a simple modification to the URL. The ability to change values in LXP would be a bad thing. For example, if I am a cracker and I figured out that the variable that set the rights level was called lxp.rights I could try to manipulate this variable via the location bar by changing the URL to look like this:
http://somehost/index.lxp?lxp.rights=5
Fortunately, because the variable is protected within the lxp-reserved object, this will not work. Thus, by using the lxp object I have protected the application (or at least, this part of it) from being compromised via the URL bar, an external (HTML) form, or any other submit method. In short, the only way to affect a reserved object is with LXP logic itself. (This is normally done with the <setvar> tag.)
On to the application. Using what we have learned above we are going to create a simple todo list tracker. The application will perform the following functions:
- Allow users to authenticate via a users database.
- Allow all users to add/view todo items.
- Allow users to specify categories that the todo items belong to.
All right, now that we know our basic application requirements, we need to create our data structure in PostgreSQL. The name of our database will be todo and it will have the following tables:
- users
- items
- categories
- customers
I included a link in the resources below for you to download the PostgreSQL schema for the application. If you are unsure of how to create tables in PostgreSQL, I suggest you look at the PostgreSQL Info site. Otherwise, if you have created your tables, we are ready to begin developing our todo application. The first component in the application is the authentication module. We have discussed the major components of this module already in this article, and now we just need to adjust it to our new data source, and add our necessary features.
The entire application runs through the index.lxp file, and thus this will be the first file we review. I have already written the application so we don't need to go through the addition of every single feature. However, we will discuss some of the standout points. The following is the top of the index.lxp file:
<dock type="init">
<if submit="Submit">
<include src="init_authquery.lxp" />
</if>
</dock>
<include src="authquery.lxp" />We have not discussed the dock tag previously, but it is an important tool. By using the dock tag we can include initialization files that are processed before any data is sent to the client (including HTTP headers). In our case, we need the file to process a SQL query to set the authentication cookies, in order to have simple, persistent authentication information within our humble todo application. Since this involves the setting of cookies, this must be done before any data is sent to the client, and thus, it is done in the initialization dock.
The following is an example of the init_authquery.lxp file:
<lxp>
<include src="dbname=todo user=nobody" sql="SELECT * FROM users where
username='$username' AND password='$password'" setvars="lxp">
</include> <if sql.numrows="1">
<setcookie name="username" value="@lxp.username">
<setcookie name="password" value="@lxp.password">
</if>
</lxp>
In this code, simply put, we execute a query that retrieves its values from an HTML form (the "username" and "password" arguments). If the SQL statement is successful, and returns a single row, we set two cookies with the <setcookie> tag. The next file processed is authquery.lxp. This file looks like this:
<lxp>
<include src="dbname=todo user=nobody" sql="SELECT rights FROM users WHERE
username='@cookies.username' AND password='@cookies.password'"
setvars="lxp">
</include> <if sql.numrows="1">
<setvar lxp.authenticated="1">
</if>
</lxp>
This file looks similar to the init_authquery.lxp. However, there are two differences. The first is that authquery.lxp is used at the top of the file before any data is sent to the client, and operates only off of submitted form variables. This ensures that any requisite cookies are set before attempting to authenticate off of them in authquery.lxp. The second difference is that authquery.lxp sets the rights level for the user on authentication from the stored cookies.
As we have placed authquery.lxp at the top of the file before anything else, we don't have to duplicate the authentication code within any included files. We do, however, use the protected lxp.authenticated variable within the subsequent application files such as todo.lxp to verify that the application was called correctly through index.lxp, and that the user was authenticated.
The following is the code for todo.lxp.
<lxp> Authenticated: <putvar name="lxp.authenticated"> <br /> Rights: <putvar name="lxp.rights"> <br /> Username: <putvar name="cookies.username"><if lxp.authenticated="1"> <if lxp.rights="5"> <h3> Hello <i><putvar name="cookies.username"></i> you are currently authenticated and you have a security level of <i><putvar name="lxp.rights"></i> You are a superuser. </h3> <hr /> Please select a task: <br /> <div align="left"> <table border="0"> <tr><td align="left"> <a href="index.lxp?task=view">View Tasks </td><td align="left"> <a href="index.lxp?task=add">Add Task </td><td align="left"> <a href="index.lxp?task=del">Delete Task </td></tr> </table> </if> <else> <h3> Hello <putvar name="username"> you are currently authenticated and you have a security level of <putvar name="lxp.rights">. You are a end user. </h3> <hr /> Please select a task: <br /> <div align="left"> <table border="0"> <tr><td align="left"> <a href="index.lxp?task=view">View Tasks </td><td align="left"> <a href="index.lxp?task=add">Add Task </td></tr> </table> </else> </if> </lxp>
The todo.lxp file is the main body of the application. It informs the user of their rights, and allows for the user, based on those rights to select a task. If you are user with the rights of 5, you may view, add or delete tasks (note that deletion is not implemented in this very basic application).
Notice that before checking rights, the lxp.authenticated variable is checked. This is done so a person could not call the file directly (e.g., http://myhost.com/contact/todo.lxp) and produce results. The user, no matter what, has to authenticate first, and as mentioned previously they would not be able to do something like this in the location bar: http://myhost.com/contact/todo.lxp?lxp.authenticated=1&lxp.rights=5
The todo.lxp functions are protected by the protected variables within the lxp object.
The last part of the application I will show you is the add.lxp. This file, although similar to the todo.lxp file, will show you how to insert data into PostgreSQL from a form using LXP.
<lxp>
<if lxp.authenticated="1">
<if task="Insert">
<include src="dbname=todo"
sql="INSERT INTO items VALUES('$item','$customer','$priority')">
</include> <div align="left">
You have inserted the task with item description: <br />
<strong><putvar name="item"></strong>
</div>
</if>
<ifnot task="Insert">
<form method="post" action="index.lxp">
<table border="1">
<tr><td align="left">Task</td>
<td><textarea name="item"></textarea></td>
</tr>
<tr>
<td align="left">Customer</td>
<td align="center">
<select name="customer">
<include src="dbname=todo"
sql="SELECT cust_name
FROM customers ORDER BY cust_name">
<option>
<field name="cust_name">
</option>
</include>
</select></td>
</tr>
<tr><td align="left">
Priority
</td><td align="center">
<select name="priority">
<option value="1">1 *COMPLETED*</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option value="5">5 *ASAP*</option>
</select>
</td>
</tr><tr>
<td align="center" colspan="2">
<input type="submit" value="Insert" name="task">
</td>
</tr>
</table>
</form>
</ifnot>
</if>
</lxp>
This file is a good example of using not only the authentication setup, but also processing data from a form. After you have logged in, you can select "Add" from the menu. When you click Add, the add.lxp file will be processed through the index.lxp file. This in turn will present you with a small form that you can use to add tasks to the PostgreSQL todo database. When you click Insert, the form will post to the index.lxp file, and be processed by add.lxp. The add.lxp file will first check if you are authenticated. If you are authenticated, it will then check to see if the form is requesting an insert. If the form is requesting an insert, then add.lxp will insert the values from the form into the todo PostgreSQL database. If the request is not an insert, then add.lxp will show the user the task add form.
Note that while basically functional, there are some caveats with this somewhat bare approach to insertion. Most notably, if you input variables including apostrophes into the code as shown (e.g., "This's my task"), this can break your SQL syntax. This dilemma can be alleviated through the use of the LXP <varparser> tag, explained in the section on Tag Parsing in Chapter 13 of Practical PostgreSQL, online at PostgreSQL.info.
In the resources section below there is also a link to download the almost complete (but very simple) todo application. I have included the PostgreSQL schema (todo.sql) and all source code for you to enjoy. Please remember that this application was written as a concept application, there is no warranty, and no guarantee. The application was written for this article specifically and may cause you to burn your toast in the mornings.
Published December 10, 2001 Reads 1,906
Copyright © 2001 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Joshua Drake
Joshua Drake is the co-founder of Command Prompt, Inc., a PostgreSQL and Linux custom development company. He is also the current author of the Linux Networking HOWTO, Linux PPP HOWTO, and Linux Consultants HOWTO. His most demanding project at this time is a new PostgreSQL book for O'Reilly, 'Practical PostgreSQL'
- Kindle 2 vs Nook
- Is Cloud Computing Like Teenage Sex?
- Confessions of a Ulitzer Addict
- GovIT Expo Highlights Cloud Computing
- Tactical Cloud Computing Panel at 1st Annual GovIT Expo
- Cloud Computing Can Revitalize Your Career as Software Developer
- Ubuntu-based Open Source Linux Mint Tests KDE Version
- Yahoo! SVP Shelton Shugar to Discuss Innovation at Cloud Computing Expo
- Virtualization Journal "Readers' Choice Awards" Voting Is Now Open
- Einstein, Sharks and Clouds: IT Security in the Cloud
- Adobe Flex Developer Earns $100K in New York City
- Amazon Web Services Database in the Cloud
- Kindle 2 vs Nook
- Cloud CEOs, CTOs & SVPs to Speak at 4th International Cloud Computing Expo
- Is Cloud Computing Like Teenage Sex?
- 1st Annual GovIT Expo: Letter from the Technical Chair
- Ulitzer News: Search vs New Media
- The Difference Between Web Hosting and Cloud Computing
- Cloud Computing Expo: Exclusive Q&A with Yahoo! SVP Cloud Computing
- Confessions of a Ulitzer Addict
- GovIT Expo Highlights Cloud Computing
- Twitter, Linked In, Ning and Ulitzer: Easy Personal Branding Strategy
- My Thoughts on Ulitzer
- Tactical Cloud Computing Panel at 1st Annual GovIT Expo
- The i-Technology Right Stuff
- Linux.SYS-CON.com Exclusive: Linus Discloses *Real* Fathers of Linux
- After Ubuntu, Windows Looks Increasingly Bad, Increasingly Archaic, Increasingly Unfriendly
- Linus' Top Ten SCO Barbs
- A Closer Look at Damn Small Linux
- Netscape Co-Founder's 12 Reasons for Growth of Open Source
- Introducing "Cooperative Linux" - Linux for Windows, No Less
- *POINT - COUNTERPOINT SPECIAL* What's Wrong with the Open Source Community?
- Where Are RIA Technologies Headed in 2008?
- Linux.SYS-CON.com Exclusive: What Would UserLinux Look Like?
- i-Technology Viewpoint: The New Paradigm of IT Buying
- Is Linux Desktop-Ready Yet...or Not?






























