Writing Scalable Applications with PHP

A follow-up to April's print article, "Real-World PHP Security".

The first part of this article, "Real-World PHP Security", appeared in the April 2004 issue of Linux Journal and covered the subject of secure PHP development. This article takes you, the professional PHP developer, one step further, by providing detailed explanations and reliable source code that illustrate the steps to follow in order to develop successful PHP applications.

One day or another, every developer faces a situation in which he/she is responsible for extending the functionality of an existing application or prepare an application for an increase in use and traffic (scaling up). Our goal today is to make this process trivial by learning to develop applications based on a clean, elegant and modular design that is secure, reliable and flexible while keeping it all simple.

Please refer to Figure 1, previously introduced in "Real World PHP Security" and included below.

Figure 1. Our Application Model Diagram

Cleaning Up the Operating Environment

As a system administrator, you may have noticed how flexible PHP is in terms of error reporting and security. The php.ini file enables you to make considerable changes to the behavior of the PHP interpreter, which can lead to bad surprises for a PHP developer.

Before we start working on the logic of our application, we must ensure that our operating environment will behave in a predictable way. One of the things you must watch out for is PHP's magic_quotes_gpc directive, which, when enabled, escapes every single value in your GET, POST and COOKIE arrays. This may look like a great way to protect against SQL injections, but it becomes a hassle when working with binary data. Listing 1 illustrates how to detect if the magic_quotes_gpc directive was enabled and how to reverse its effect if necessary.

Listing 1. Cleaning Up the Operating Environment

Many other surprises out there waiting for you as you port your applications to different platforms. Generally speaking, you should become as familiar as possible with the directives available in php.ini. Also, use the ini_get() PHP function to find out if specific directives are enabled or not. You then are able to set up your environment in a predictable way without having to worry about the configuration of the PHP interpreter.

Database Connectivity

If you are developing a commercial application or would like your application to be as flexible as possible, one thing you should look into is using a database abstraction facility in your projects. Many database abstraction libraries are available, but PEAR::DB is a widely accepted standard that performs well, has great error handling and is quite reliable. DB currently supports 13 different database platforms. DB's documentation is quite extensive and can be found here.

Some may argue that using a database abstraction layer in your application can affect the overall performance. It does, though, bring the flexibility you need to scale your applications up to new levels and to release cross-database applications.

Although DB may not seem forgiving or friendly at first, the DB APIs are compliant with the PEAR standards, which makes its behavior predictable and allows developer to create wrappers easily.

As with any database API, the steps to perform operations on your database are as follow:

  • Establish a Connection to the Database Server: DB uses a DSN (data source name) to represent the parameters to use when establishing the connection. Many formats are supported; an example might look like this: mysql://dbuser:dbpass@localhost/db_name. You then can use DB::connect(&$dsn) to establish the connection.

  • Perform Error Handling: DB uses the PEAR standard for its error handling facility. This error handling system is well designed and is versatile enough to provide predictable error control for all PEAR packages.

  • Specify the Behavior of the Interface: This is where PEAR::DB truly shines. DB allows the developer to define how the package should operate in every aspect. Using the same interface, you can make DB work as a cursor-based result-set iterator or fetch your entire result-set in an ordered array, an array of objects or an associative array.

  • Execute Queries: Whether you want to execute a stored procedure or a simple query, DB provides simple methods that perform those operations on your database while still providing error handling. The query() method simply executes a query against your database and returns a PEAR error object if an error should occur.

  • Work with Result-Sets: DB offers many simple methods for working with result-sets and offers a myriad of data-structures to the developer, such as associative arrays, objects, indexed arrays and so on.

But DB also offers some higher-end methods to the developer, such as auto-prepare and auto-execute facilities that allow you to create templates for your SQL query and have DB handle the creation and execution of subsequent queries. It also can filter literals against special characters, regardless of the database server you are using.

______________________

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

PEAR::DB is too slow!!

Sajid's picture

http://www.onlamp.com/pub/a/php/2001/11/29/peardb.html
http://markmail.org/message/c2aik7tba25j4coz

If PEAR::DB is toooo slow, how do you want scale up (!!!) your application using it?!

I think, you are calling a good (maybe better) application design - scaling up the application!
BUT What about increasing users/hits like facebook guys are facing?

PEAR::DB is too slow!!

Sajid's picture

http://www.onlamp.com/pub/a/php/2001/11/29/peardb.html
http://markmail.org/message/c2aik7tba25j4coz

If PEAR::DB is toooo slow, how do you want scale up (!!!) your application using it?!

I think, you are calling a good (maybe better) application design - scaling up the application!
BUT What about increasing users/hits like facebook guys are facing?

Keep Looking

Anonymous's picture

The architecture in this article is neither scalable nor secure. Scalability usually implies the ability to build some sort of N-tier architecture so that processing can be distributed across multiple servers if necessary. As for security, I can imagine an application that contains code like the following (line 19 in user.php) could be too secure:

return $_GET['action']($index_content);

Just imagine the code injection a malicious person could do with that.

There seem to be two general type of frameworks in PHP:

- ones like this with a sloppy design glued together with global vars and assumptions,

- and others that copy pattern happy, first generation Java frameworks (which Java is starting to abandon) that are so absurdly complex that they do the worst things you can do in PHP: make it slow and a chore to program.

You are usually better off in PHP either programming to the metal or using an old school, PHPLIB, kitchen sink style libraries. And then there is PEAR (am I the worlds biggest, most incoherent framework or the worlds smallest, least coherent repository?)

Does anyone know if a PHP framework that:

- respects PHP's wonderfully simple request and output systems,

- has a lightweight front/application controller that provides basic dataflow/action chaining,

- isn't any more object oriented than PHP actually is,

- provides simple request filtering and validation (preg_replace anyone?),

- allows for some N-tier application separation,

- and doesn't impose a specific DB/DAO or Template/View,

- is customizable enough to go as simple or complex as needed,

- maybe even allows either procedural or OO programming.

I would love to hear if anyone knows of such a thing. Maybe it is time to write it.

:)

Sajid's picture

You probably need to write it by yourself and I think, it's even better...

I personally use my own framework to develop applications using PHP (just don't like other frameworks!) and I made it exactly what I want from a framework (and minimal/simple at the same time). Sweet!
:)

Re: Keep looking

Sandeep's picture

I think http://www.jaws-project.com/index.php might interest you. It is a breeze to install it and also it makes MVC for procedural programmer like me easy to understand. I know MVC in theory and it shows a good example of how to implement in PHP.

Regards

I am all for your wishlist

Anonymous's picture

I am all for your wishlist of the 'Keep Looking' poster. I hope Zend Framework does not fall into the trap of overengineering and too much of MVC crap from Java domain.

In the meantime I found http://phx.sourceforge.net/ that seems to have most of the attributes that you enumerated. It looks remarkably simple but I am hesistant to use it since it does not come with a user and security management

Re: Keep Looking

Anonymous's picture

Does anyone know if a PHP framework that:
- respects PHP's wonderfully simple request and output systems,
- has a lightweight front/application controller that provides basic dataflow/action chaining,
- isn't any more object oriented than PHP actually is,
- provides simple request filtering and validation (preg_replace anyone?),
- allows for some N-tier application separation,
- and doesn't impose a specific DB/DAO or Template/View,
- is customizable enough to go as simple or complex as needed,
- maybe even allows either procedural or OO programming.

I've authored MVCnPHP which is a minimal MVC framework that would let you do much of what you want here except allow for procedural programming. I think using MVC sort of implies OO is the way to go though I can see how allowing procedural commands, views, etc can be done but that reintroduces some of the things the MVC would be acheiving (more atomic code, more maintainable, etc.) You can learn more about MVCnPHP here .

You are right, though, frameworks don't ensure any sort of scaling. DB-based session handling via PHP sessions and allowing true mutiple web and db servers get you that.

Re: Keep Looking

Anonymous's picture

Also, quit dinging PEAR. PEAR has a number of useful classes and if you are hosted, you can still use PEAR despite restrictions on the host by modifying PHP's include_path through code using ini_get and ini_set. Also, people tend to compare PEAR to CPAN and similar repositiories and that isn't apples-to-apples.

Re: Keep Looking

Anonymous's picture

But PEAR deserves it. I agree it has a number of well coded and useful classes. But the point is: what is it? It's sure not CPAN which is a code repository with a great installer. PHP could use a great repository so you wouldn't have to search a dozen sites to find code. And the PEAR installer is definitely the best part of PEAR.

It's not a framework even though they claim to have some crazy "no conceptual duplication" rule. The code quality is uneven. It is not coherent. And much of the code is totally bloated. PEAR.php is unnecessary and should have just been some standards for method names (like error handling and reporting). Even they admit that the PEAR_Error is terrible.

They are the official code repository and are installed with PHP. They should be held to a higher standard.

I think they need to 1) open the repository to everyone with minimal requirements (like CPAN or SourceForge) and 2) come up with a core set of classes that are a coherent base on which to build a medium size site. They should, for practical reasons, leave enterprise scale stuff at the high end and small things like email forms at the low end for others in the repository to solve.

Re: Keep Looking

Anonymous's picture

Apparently, you have not read the code illustrated at all!

The line return $_GET['action']($index_content); is inside an IF statement. If I remember correctly, it's something like this:

if (in_array($_GET['action'], $allowed)) {
return $_GET['action']($index_content);
}

so your entire comment makes absolutely no sense since code injection is not possible.

Also, please don't confuse the article with an actual framework.
The code is provided as a draft to illustrate the points brought up in the article.

Thanks,

Xavier

Re: Keep Looking

Anonymous's picture

I read his article, looked at the code, and learned from it. I also read the comments and learned more. I even went and improved some of my own code after writing my post. It would be helpful if the writer actually joined the conversation about writing better PHP code rather than just becoming defensive.

"so your entire comment makes absolutely no sense since code injection is not possible"

Actually very little of the comment was about code injection. The point was not to find one bad line. I just think one goal of presenting a secure application framework is to promote safe access to the request. You mention magic quotes yourself. I think perhaps a better method is have all access to the request go through filter functions. That way you don't miss anything, which is easy to do when you directly access the PHP globals all over your code. Those functions can also centrally handle php.ini settings which you also mention.

I apologize if you took offense. My comments were to express my thoughts about PHP applications, security and scalability. I just don't think the code you presented addresses those issues very well.

Re: Keep Looking

Anonymous's picture

Reading my previous comment over again, I understand that I may have overreacted.

However, please understand that the article is in no way intended to present a *framework*. The source-code provided is a good illustration of the patterns described in the two articles, no more.

Also, I agree that requests should be filtered, which is actually illustrated in Figure #1. I do have some code that does just that if you are interested.

The purpose of this design is to provide every module with a predictable environment (initialized by index.php and config.inc.php) where every module has a database connection available, knows what to expect from request variables, knows what the user is trying to do at any point. Using this, you have a central facility to provide security and scalability to your applications.

The article was never intended to be read as "If you want to write scalable and secure apps, use the attached code" but simply "With a design like this, you can really focus on implementing security and modularity because your environment is predictable, centralized and efficient".

I did my best to provide a lot of comments in the code to point the developer in the right direction as to where they should spend some time implementing such things.

I will gladly continue this conversation on here, or by email.

Thanks,
Xavier

Re: Keep Looking

Anonymous's picture

You should look at http://logicreate.com, the answer lies within.

Re: Keep Looking

Anonymous's picture

I've not looked at the code but the example you gave is typical of somebody with zero coding experience. The biggest problem with PHP has nothing to do with the language itself, it's a human by-product of PHP's ease of use. That people are writing articles and distributing scripts containing such terrible code is giving PHP an undeserved bad name.

PEAR is possibly the most foul pile of OOP::POO I've ever seen, but it's targetted at people with a shared hosting account and not at anybody doing serious work. I suspect PHP5's strip comments and whitespace function will be used to speed up the PEAR libs in production enviroments, stripping comments alone should reduce them to 1/10th the size.

We're working on porting our framework to PHP5, the object model is greatly improved and it should finally let us clean up our code. As for scalability, it's usually the backend db that is the bottleneck, PHP has no inherent scalability because it doesn't need any!

Re: Keep Looking

Anonymous's picture

Maybe it is time to write it
Do it!

isn't any more object oriented than PHP actually is,
Glad somebody said it.

Having said that experimenting and trying new things with php is important. I do hope the java phase passes soon though

Webinar
One Click, Universal Protection: Implementing Centralized Security Policies on Linux Systems

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Learn More

Sponsored by Bit9

Webinar
Linux Backup and Recovery Webinar

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.

Learn More

Sponsored by Storix