Hacker News new | past | comments | ask | show | jobs | submit login
Securing PHP (jamescun.com)
110 points by jamescun on Oct 17, 2011 | hide | past | favorite | 70 comments

What's missing from just about every PHP app and PHP framework is this bit of Apache config that prevents execution of trojan PHP scripts:

    <Directory /var/www/website>
     # Only execute /index.php and no other PHP files
     RewriteCond %{REQUEST_FILENAME} -f
     RewriteCond %{REQUEST_FILENAME} .php$
     RewriteCond %{REQUEST_URI} !=/index.php
     RewriteRule ^(.*)$ not_happening [L,F]

    # Remove other file types from PHP execution
    RemoveHandler .phtml .php3
This way attackers can upload whatever PHP file they want but they can't execute it though an Apache request.

What if the attacker names their trojan "index.php"? Doesn't matter, only top-level index.php of the site can be executed.

I'm reading this, and I'm just dumbstruck that, in over 15 years of development, that this is actually a recommended solution to PHP security. This isn't a knock against your configuration; I'm sure it's (probably) fine for your usage, but whatever happened to properly sanitizing and sandboxing uploaded content?

I mean, I'm trying to imagine another web application language where "attackers can upload whatever (X) file they want" is even a valid case, ever. I mean, imagine a war file being wholesale replaced-- it isn't possible without going out of your way to misconfigure your app server. This, I think, is the base problem with PHP; the default configuration is predicated upon content and code not being segregated at all, and hot redeploy is the norm, without any notification to the admin that it's actually happening.

If you're writing the app, you're absolutely right. Apps should be written in such a way that everything is properly sanitized and sandboxed.

Unfortunately, a lot of people who use PHP are stuck with third-party apps with questionable security records, such as WordPress. If you want to have anything resembling security in such an environment, you need to resort to band-aid solutions such as disabling functions. It's far from optimal, I admit, but at least it helps reduce damages if (or rather, when) the third-party app gets hacked.

Okay, yes, a considerable amount of blame lies with apps and frameworks that have security holes. But here's the thing: make the runtime secure /by default/, so that -- if you really want to run Wordpress, you have to uncomment the PHP configuration labeled "this is extremely hazardous and will likely result in your machine getting compromised" and I think you'll find those third-party apps and frameworks cleaning up their act in a hurry.

Many of those features are completely harmless if used correctly. By itself, exec() doesn't cause your machine to be compromised. It is a valuable function that every scripting language should have. (Would you like Python to disable os.exec* by default just to make websites more secure?) Besides, incompetent developers will always find a way to make vulnerable apps using even the most benign features. The only way to make a runtime secure against fools is to allow nothing.

There is also the logistical problem that if the default runtime can't run popular apps such as WordPress, people will simply switch to a broken runtime instead of cleaning up WordPress. This is a particularly big problem in shared hosts who need to make their service compatible with everything or risk losing business. It's been difficult enough to get them to adopt PHP 5.3.

On the other hand, safe_mode, register_globals, magic quotes, etc. can and should be disabled by default. Good news: The PHP team is finally getting around to deprecating them. Also, I use dotdeb's FPM packages on my servers, and dotdeb's default configuration tends to be pretty good.

"Would you like Python to disable os.exec* by default just to make websites more secure?"

Yes! Under no circumstances should you ever be spawning new processes from your web application on the fly, ever. You should be using trusted communication to an existing worker thread that is fired up on application start and then never touched except for IPC (think Akka), or trusted communication to an existing process on another machine separate from your web / app server that you can start or stop yourself, separate from the web process.

"Besides, incompetent developers will always find a way to make vulnerable apps using even the most benign features."

Very true; however, you can make it extremely difficult to do so, and you can effectively limit the damage in case of breach. That's what most of the configuration is, from the parent article. Stop someone from being able to write an arbitrary file on the filesystem, by telling them to either store a blob somewhere, or sending data to S3, or whatever, and it will be extremely hard to overwrite existing application code that gets re-interpreted every time it's updated.

"There is also the logistical problem that if the default runtime can't run popular apps such as WordPress, people will simply switch to a broken runtime instead of cleaning up WordPress."

Disagree-- the onus is on Wordpress to keep up with the current version of whatever language they decide upon. When PHP version X disallows re-compilation of scripts on the fly without some sort of notification or server restart, some people and hosts will stay on version X-1, sure, but that's going to be really hard when every distribution starts packaging version X. Wordpress, PHPBB, etc., will need to go through some development pain, but ultimately those packages will wind up being more secure.

The reality is that these kinds of articles shouldn't have to exist. I'm even a little shocked at the Java community, because Red Hat's documentation on "How to Secure JBoss" actually exists, too-- remove jmx-console, remove web-console, and limit access to the http-invoker and jmx-invoker services (and that's it). What Red Hat should be doing is to have a "production" configuration that does all these for you.

IMO, the plethora of poorly written articles and tutorials is the ultimate culprit here. You'll find few go into detail regarding file extensions vs. mime types, file permissions, file ownership, or anything under the hood. When a beginner is left to their own devices with some sample code that doesn't mention the implications of not taking security seriously, we're left with swiss cheese implementations.

This may inherently be due to PHP's age. As an early dynamic language, it could be expected that the earliest shared source code and tutorials would likely contain bugs.

> it could be expected that the earliest shared source code and tutorials would likely contain bugs.

Unfortunately, a lot of recent PHP tutorials published in seemingly up-to-date websites also contain WTF code. Case in point: this tutorial [1] showed up on reddit a couple of days ago.

[1] http://www.anil2u.info/2011/06/object-oriented-programming-i...

Nowadays, I view any PHP code outside of Stack Overflow and Github with the utmost suspicion.

A couple of days ago a tutorial "PHP MD5 Secure login script" showed up on Hacker News:


The article has later been removed from the site.

Same idea, but for nginx:

            server_name  domainname.com;

            root /srv/sites/domainname.com/httpdocs;
            index index.php;

            access_log  /srv/sites/domainname.com/logs/access.log main;
            error_log   /srv/sites/domainname.com/logs/error.log info;

            try_files $uri $uri/ /index.php?$query_string;

            location ~ \.php$
                    try_files $uri $uri/ /index.php?$query_string =403;

                    include /usr/local/nginx/conf/fastcgi_params;
                    fastcgi_pass                   phpfpm;
                    fastcgi_param SCRIPT_FILENAME  $document_root$fastcgi_script_name;

You've missed a few file types -- I see that you've got "phtml", but a lot of web servers will also parse files with stupid extensions including:

    .php3 .php4 .php5
    .ph3  .ph4

"every PHP app"??

What about apps that don't limit themself to just index.php?

I never understood this obsession with having everything flow through index.php. Apache already has a method to dispatch requests to the proper controller AKA file. Why rewrite it again?

This is fictional security. If someone can upload a file, they can also upload index.php (and from my experience cleaning up a few hacks, that is exactly what they do).

And if you (correctly) set it so they can't write to the top level directory, what you really should do is remove the php handler from the directories they can write to.

Having everything go through index.php (the "front controller") makes it a lot easier to manage common libraries and use PHP's autoloading capability. You don't have to add a bunch of includes to every script. You don't have to change every script if you decide to replace one of the common libraries. You can force every request to go through the same set of checks (such as authentication). You can have pretty URLs like "/blog/post/123".

The front controller pattern doesn't have much to do with security, though. It also doesn't work with apps like WordPress.

I personally run my applications entirely through index.php but your argument does not make sense. You can easily include one file at the top of all your scripts and have that handle things like autoloading, authentication, etc.

Then if you need to make a change you are still only changing it one spot.

If you have a front controller, you don't even need to repeat that single include in any file. Why repeat the same include in 100 different files if you can avoid it? Also, what if you realize after a while that you need to change the location of the single include file because you carelessly placed it in a publicly accessible directory (bad for security) ? Now you have to edit 100 files.

Another reason: What would your templates look like if your app had 100 different entry points? It would seem silly to have 100 template files in addition to 100 PHP scripts. So the developer is most likely to mix business logic with templates in the same file(s). Not good.

Of course, if you're a good enough developer to know that you should avoid problems like this, it doesn't really matter how you organize your site. But I think that the front controller pattern helps to push developers (especially novices) toward the right direction.

No, just because a site allows users to upload files doesn't mean they can replace the top-level index.php, for if that were true then whoever setup that server needs to look for job opportunities in the circus.

The problem with removing the PHP handler from all other writable directories is the reality of dealing with many 3rd party modules, themes, and apps that have their own upload directories, and sure you can audit all 3rd party code and rewrite it yourself, but you should also assume the code is full of holes anyway and configure the other layers in your stack according to the principle of least privilege.

"I never understood this obsession with having everything flow through index.php. Apache already has a method to dispatch requests to the proper controller AKA file. Why rewrite it again?"

How? Is there a way to let Apache, for every request to host.domain.com execute /var/www/site/index.php ? I've seen a post somewhere claiming that years ago, and I've tried many times to get it to work or re-find that post but I never managed to do so.

Yes, there is a way by rewriting (not redirect) the url.

    RewriteEngine on
    RewriteCond %{REQUEST_URI} !^/index.php
    RewriteRule ^/(.*)         /index.php/$1
I didn't test it, but it's probably as simple as that.

But that's not what I meant. Instead of having index.php look at the url parameters and include the proper controller, just directly execute that controllers .php file. Make a file that you include in each controller that does any prep work you need and that's it, let apache execute the controller directly.

Yes, using mod_rewrite is what I've been doing for years. My question was on the second situation - how do you let Apache execute the controller directly?

I would prevent uploads of arbitrary PHP files. If they are not parsed by the PHP interpreter, they might be delivered as PHP source code, like an ordinary text file. This could be used to be included into another vulnerable website. So your website is part of an attack, the malicious code is on your server, but remotely included and executed on another machine.

Also, if nearly arbitrary PHP files can be uploaded, the chances might be good that it's possible to upload other files as well, like some additional .htaccess files for subdirectories.

> What if the attacker names their trojan "index.php"? Doesn't matter, only top-level index.php of the site can be executed.

As an alternative, you can simply gzip all uploads automatically. You will save hard drive space and prevent any funny business.

Ideally though, you should make sure that anything not part of your system, doesn't get passed through PHP. This will take away this common security risk, as well as limit the overhead required to serve those files.

> Ideally though, you should make sure that anything not part of your system, doesn't get passed through PHP.

For you to upload a file to your system it has to pass through PHP. That's where the problem is. Once it's on your system, it can be executed by other means ... those means not necessarily being Apache or NGINX. By encoding the upload, you not only reduce the size, but also render it harmless.

Just a thought: can we find some input, which will turn into a malicious script, when compressed or encoded by an algorithm and saved as a file on the server? The encoded file could contain something like <?php ... ?>. If the server could be tricked into parsing the encoded file for PHP, we are in trouble. I think about uploading an additional .htaccess, which will contain a directive to send .zip files to the PHP parser - of course this should never be possible.

There are some encoder/decoder tools on the web, where it is possible to enter, for example, base64 encoded strings and get these decoded. It is often possible to enter base64 encoded JavaScript plus some closing tags or brackets to break out of the input field. When decoded, the JavaScript will be executed by the browser and we have found a cross-site scripting flaw.

> Just a thought: can we find some input, which will turn into a malicious script, when compressed or encoded by an algorithm and saved as a file on the server?

This is not possible with gzip:


I should mention that on top of this technique, I also rename all files uploaded to a random hash that is stored in a database. That hash is never revealed to the client. When the file is downloaded, the real name is provided from the database as the file name, while the source of the file is read from its true location.

So even if an intruder were to upload a malicious file and somehow managed to bypass the encoding algorithm ... he wouldn't know where to find it. He would have to hack the database on top of everything just to find out where it is.

what i do is to serve user facing php files as .html and keep backend includes as .php

then just block apache to serve anything .php

this usually get me covered of most backdoors bugs in pear and such. ...not that i do that because of this reason. it was first only for organizing the code tree.

But this usage of hidden php can sometimes be detected. If expose_php is not Off, you can see the X-Powered-by HTTP header and the PHP version, if the requested page was a PHP ressource.

You can also try to get the PHP eastereggs displayed with something like this, on a PHP generated page:


Trying to provoke errors or weird PHP specific behaviour, maybe with PHP error messages displayed, is another way to gather some informations about the script language used by a site. But this is already more aggressive than simply looking for an X-Powered-By: header.

Just rewriting the file extension does not make a site any safer. Omitting file extensions is generally an interesting alternative, because in case you change from .php to .aspx or whatever, all URLs stay the same. Cool URIs don't change.

I think there probably is some security in changing or omitting file extensions in your URIs. It seems that an awful lot of exploited sites are attacked opportunistically - you find an exploit, find a suitable search term, and google up some victims. If you can move yourself out of matching those general results, you gain the (small) benefit of not being hit by all those automated scan/'sploit scripts.

Yes, it's security through obscurity, and is absolutely not something you should rely on, but it can reduce the number of people giving your wobbly-looking front door a kick.

Of course, if everyone starts doing this, the scanners will switch to more robust methods of testing for your language and server types and versions.

I couldn't care the slightest about exposing php. Only safe bet is to assume your public facing services will be compromised at one point.

it was a decision mostly done by usability and code clarity (separate presentation scripts from data/model ones)

But one benefit of not having the regular setup, is that even if i'm a victim of an automated attack, it will probably fail because it did not expected to not be serving .php or .phtml files as php. For a skilled targeted attack i'd still be as hopeless as the person hiding php.

had that happen when one box was compromised because of a ssh key bug. but it turned out, the attack was automated and had vectors that worked with linux x86 and several common unixes. i was running irix on an very old box. so i had just some weird log entries instead of a root kit. not that it prevented the paranoid i am to wipe the system as if i had a root kit.

I see you marked the cURL functions as "dangerous", advising people to disable curl_exec and curl_multi_exec. This disables all apps that do HTTP requests (except those that communicate through the socket functions). Is there any particular reason why you consider cURL problematic?

Hope you are running with a curl version that can't redirect to a file. Check your CURLOPT_REDIR_PROTOCOLS options.

You are correct, that was a mistake on my behalf. The post has been amended.

Disabling parse_ini_file looks like a mistake too ;)

(It's just a ini file parser; it has nothing to do with PHP settings.)

I typically disabled it because (historically, not 100% sure now) even with restrictions in place, you can still read PHP.ini and (not now mind) you could also write to the INI config with the ini functions.

> You can still read PHP.ini

You can always detect the contents of php.ini using functions like ini_get. Disabling those isn't recommended, as a lot of applications use them legitimately to read things like memory_limit or safe_mode.

> You could also write to the INI config with the ini functions.

That sounds really unlikely, unless you had php.ini owned by your Apache user or you were running PHP as root. Either one of those possibilities would have left you open to much worse problems.

Perhaps you're thinking of ini_set? That only affects the current request; it doesn't have any long-term effects, nor does it write to config files.

parse_ini_file is highly useful if you want to avoid tumblr's php file sensitive exposure problem of includes.

Could you explain this a little more, please?

I'm referring to Tumblr's typo that did not render the PHP script and due to an include, it was displayed as plain text: http://news.ycombinator.com/item?id=2343330

You can see some discussions within on how to avoid it.

Also look in to Suhosin[1] from the Hardened-PHP Project

[1] http://www.hardened-php.net/suhosin/

I've looked into that, but the last update was 5 years ago. I realize it's a patch, so it doesn't necessarily correspond to a particular release, but is it up to date for modern PHP installs?

I'm not sure where you see that - the latest patch is available for 5.3.7 at http://www.hardened-php.net/suhosin/download.html

It's not up to date with 5.3.8 or 5.4 - but they are always slightly behind - but not 5 years behind.

Edit: Now I see that their news page is really out of date - my bad.

Ahh yes, thank you. I had always noticed the homepage lists the last release in 2006 and the documentation seems to be about the same and I never got to the downloads page.

I'm not sure where you're looking, but there are up-to-date patches at:


Thanks, added it to the post.

That's pretty sound advice. However a lot of scripts won't work if you disable exec and co.

some other random ideas for php-security:

If you have to enable some form of option to exec binaries be aware that open_basedir is useless now, because the attacker can just start a python instance and operate under apache user if you are using mod_php

using fastcgi (mod_fcgid or nginx+php-fpm) and restrictive permissions on your directories should at least protect your other users home directories.

another idea is prevent malicous scripts is to firewall apache and php from iptables. there is an iptables module for restricting uid and gid ranges to have access to the outside world. this could at least prevent a trojan dropped in /tmp to connect to their irc-server. but you can also disallow outgoing traffic to port 80, this breaks however all the auto-update features of e.g. wordpress.

A lot of script-kiddie toolkits can also be stopped by not having gcc,wget,python etc.pp available to the user running php.

if you have to host sensitive data on the same host as the php application it's wise to use a jail or at least chroot for php, there are some guides to put a mod_fcgid php into a chroot

and: never ever use the mysql root user for database connectivity!

If you don't know much about PHP security, the single best step to secure your installation is to start by using the recommended PHP.ini file for a production deployment (often called php.ini-production or php.ini-recommended). This will set sensible defaults you can tweak for your own app.

Also, open_basedir is nice and should be used whenever you can but it doesn't match a system-wide chroot.

Sometimes you really need to invoke external commands through exec(). In those cases, make sure to use escapeshellcmd() and escapeshellarg().

Those are some good tips, however, the memory and script execution limits you're setting there will not play well with any sort of CMS or Framework. Wordpress, Drupal, Symfony all will need an occasional (or perhaps regular) bigger load. Minimally, maybe you could leave a note that custom settings should be made for these systems. I can just see hordes of wanna be sysadmins (like myself) going out and making all the changes you've said and unnecessarily break WP.

You're right about the 8M memory limit, but I don't think there's anything wrong with the 15 second execution limit. No page should take over 15 seconds to generate.

What about upgrade scripts (usually done via the web interface)?

Some flush()s output out to the browser (to show some initial feedback), but continue to process and send further output as the upgrade continues.

First off, under disabled functions, 'eval' needs to be number one.

Secondly, I was kind of disappointed that this wasn't an overview on common mistakes users do when learning PHP. This feels basically feels like teaching someone how to enable safe mode, because you aren't teaching someone why they should escape sql or why they should encode user submitted content, which to me is much more important. (Though teaching someone to install Suhosin and disabling debug output is still important in my opinion, so props for that)

It is a valid point, perhaps I should do a followup, showing how these settings affect PHP and examples of how someone could exploit them.

It usually get's to my nerve when people jump in the "PHP is inferior language because I decided so" bandwagon, but this kind of security strategy ind of gives some base for such criticism.

Disable external execution functions, eval, disable disable, disable. It appears to me that this is following the approach of disabling everything and nothing, then start coding without any security concerns, because you 'secured your PHP'.

I'm not a security obsessed person, but after hearing so much fuss about PHP lack of security I headed up to milw0rm a few years ago to see what it was all about. To my surprise (not so much) all the exploits were based on non sanitized user data.

Why would you use user data without sanitizing it? Why would you protect yourself against a file the hacker uploaded? (they should not have uploaded it in the first place) Why would you feed exec, eval, etc with potentially dangerous content?

If a programmer is stupid enough to do so, disabling such functions won't prevent him/her from screwing up big time some other way.

My advice: write proper applications with proper standard security in mind. It's not that hard.

The problem of working with unsanitized user input is not specific to PHP, this has been a problem with other server side scripting languages as well.

Here is an ancient example: NT Web Technology Vulnerabilities, written by rain.forest.puppy, Phrack Magazine Volume 8, Issue 54 Dec 25th, 1998.


This is one of the oldest articles on SQL injection I know of.

Man, I so wish I had published or even just posted it on a newsgroup (usenet). I discovered/thought of SQL injection in 1996 (with ColdFusion code), but my boss refused to let me disclose it to anyone (I was young then and actually listened to him).

He was going to do some big conference or something on the subject and drum up new business, but nothing ever came of it.

That's what I am trying to say. Common security practices will put you out of danger. I'm confused why we should have recipes to 'secure PHP'. Why don't the regular security measures simply apply?

My guess is that many don't know what they are so they apply follow 'secure PHP' guides and feel safe, though they are not.

Isn't "secure PHP" an oxymoron?

When written properly, a PHP app is probably just as secure as one written in any other language.

You're saying that coding in PHP, with all the myriad security holes found in PHP's implementation over the years, for which hacks have been added to disable PHP's functionality as "security hardening", is just as secure as an application which when written in a different language doesn't need its functionality removed to be secure?

What planet are you from?

Care to give a few examples so we know which angle you're coming at this from?

Using a search engine would give you numerous examples (c.f. https://duckduckgo.com/?q=php+security+hole )

Actually asking for examples sounds like a trolling attempt to me.

Not far from every piece of tech used on the web by a fair % of servers has had holes discovered. If you're trying to say that PHP is so much worse, then just saying that the previous sentence applies to it is meaningless.

Except that building a "properly written PHP app" is way harder than in almost every other language in widespread use.

The number of pitfalls and traps you can fall into almost surpasses the 'safe' parts of the language (and its environment).

I think the major problem is PHP's 'noob friendliness'. To achieve that it goes out of its way to mitigate and recover from bad code and thus doesn't have a decent set of well known good practices to code against.

The huge vulnerability that opens up is that of data validation, and you can tighten up your server config all you want, but it won't mean shit without any of that.

Of course, since PHP is such a comparatively simple language, everyone thinks they're an expert once they know how to open a mysql connection (through the now deprecated bindings, of course) and code a simple blog script with basic CRUD functionality.

As a result, there's a 'simple/complicated' dichotomy when it comes to online documentation and tutorials, where the beginner developer ignores the complicated (and typically well thought-out) stuff, and goes for what they can easily copy and paste or get their head around.

Typically none of that code has any sort of validation or sanitisation. Half of it might go on about `magic_quotes_gpc` and `mysql_real_escape_string` and other PHP4-tastic curios, and the rest won't even mention that because checking user input is seemingly only related to db communication.

I feel pretty strongly about it because I've seen people post code snippets for PHP, trying to be helpful, but the code is dangerous. They serve better as examples of exactly what you shouldn't do.

And the one thing PHP beginners (and intermediates) need is better, simpler explanations of responsible coding practices, and how it isn't hard to do at all (it's only tedious); because the sooner they know, the better.

I should write a book or something.

I know you aren't saying otherwise, I just wanted to add a bit to your "well known good practices" part. The fact is, in the professional PHP community, there are very much well established best practices (granted, not all our universal), but most are well established. The problem is, the leap from the beginning community to that professional community isn't natural. This is mostly a result of php.net catering to the beginner. It opens the doors to everyone.

Honestly, I feel there are a large number of quality sources for writing good PHP code. The problem is that isn't not all focused on PHP.

"everyone thinks they're an expert once they know how to open a mysql connection"

How true.

PHP is deceptively easy. It's akin to C, in that it will allow you to shoot your own foot if you ask it.

Yeah. I've also found that some well-known good practices might be well-known in an abstract concept but when it comes down to pure implementation it's a lot more murky.

Like you say though, that leap from beginner to experienced is so large as to make practical code examples rather scary, and you can't get anywhere if you're not confident with experimentation.*

The other problem is that there are many ways to skin a cat and one brilliant solution might be unworkable for another person. But that's just a characteristic inherent of any creative pursuit.

This thread's inspired me to try making a nice HTML5 presentation or something that outlines some of these practices as a beginner's aid. Like how Dive Into HTML5 really helps you learn what you can actually do with the new additions.

*It's surprising how many people won't experiment because they're worried about breaking something or blowing up their computer, and that irrational risk aversion just makes it difficult to learn what you can and can't get away with; and difficult to jump into the unknown.

Some of us need a language to hold our hand. Some of us don't. Some of us enjoy the freedom of coding the way we want to code, without a language shoving some perceived notion of correctness down our throat.

> Except that building a "properly written PHP app" is way harder than in almost every other language in widespread use.

This makes no sense. PHP doesn't force you to do things the right way, but it doesn't force you to do things the wrong way either. It just doesn't force you either way.

Those of us who know what we're doing can make intelligent decisions ... and those of us who can't, shouldn't be writing in PHP.

No one can make an intelligent decision until they know what an intelligent decision is. And everyone starts off at the beginning when they're picking up a new language (or want to start learning).

To be dismissive of those who 'don't know what they're doing' doesn't necessarily help make those intelligent decisions better known and easier to understand, or why they're the intelligent decisions in the first place.

> No one can make an intelligent decision until they know what an intelligent decision is.


> And everyone starts off at the beginning when they're picking up a new language (or want to start learning).

Yup. PHP is a terrible language to be your first. Its loose nature, which allows an expert to sculpt beautiful code, is a noose upon which to hang oneself as a novice. Before I started on PHP (more than a decade ago), I already knew BASIC, C, and Java. Contrary to popular opinion, PHP is not a starter language, even though it is very easy to start.

Can't disagree with any of that (other than that I don't think PHP is necessarily conducive to creating truly beautiful code). I think it goes the other way too: starting off with PHP doesn't give you a good idea of what other programming languages are like, and you'll find many things you grow accustomed to (or rely on) turned upside-down.

Maybe it's like learning to break the rules before you even know what they are?

* although to counter that, you can do some crazy things with it if you know how to. I abstracted Drupal's path finding method (drupal_get_path) into a magic static class. It's probably got a performance hit but it's bloody nice to look at:

    Module::module_name('css', 'example.css');
    // vs.
    drupal_add_css(drupal_get_path('module, 'module_name').'/css/'.$file_name);

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact