
PHP Commandments - mootothemax
http://biasedphp.com/php-commandments
======
pilif
_> 7\. NEVER send emails directly from web page code Sending emails is slow.
Incredibly slow. Don't tie up a precious web front-end process with doing so.
Use a message queue instead._

Well. MTAs are message queues. Why use a third party software speaking a
third-party protocol, adding more complexity only to eventually be talking
SMTP anyways. As such, my message queue is a locally installed MTA listening
on port 587, talking SMTP.

This is as fast or faster than any message queuing system you can come up
with, but as it's managed by the OS, it's bound to work much better than
third-party solutions.

I also get a lot for free in exchange. Stuff like automatic resending,
queueing, queue management and so on.

As such, I would not strictly agree with point 7 in the article. Sure - don't
send mail by talking to a _remote_ MTA, but if it's running inside of your
local network, using any other queuing system provides nothing but overhead.

Furthermore:

 _> How do you set up Nginx so that it won't die or kill your server when you
receive a big burst of traffic? You install it._

No. You are shifting the burden of correct app server configuration from
apache to php-fpm or whatever other process manager you're using.

In the end it doesn't matter much whether you're down completely
(misconfigured apache) or still somewhat capable of serving static files while
unable to serve any dynamic pages (misconfigured php-fpm).

------
daniloassis
I would add the following:

General tips:

* Understand how HTTP works (sounds trivial for a PHP developer, but at least here in Brazil, a huge portion doesn't do)

* ALWAYS keep php.ini with production settings and replicate the same into your development environment (Vagrant is a great option here)

* ALWAYS keep Apache or Nginx configs in sync among every environment

* NEVER trust $_SERVER['REMOTE_ADDR'] to get client ips when you are behind a Load Balancer (most modern frameworks already treat this, but make sure you are parsing it correctly)

* ALWAYS use `realpath` when you are symlinking folders

* Be REALLY careful when using `setlocale` for something, specially with numbers

* 2 basic things about Cookies: use `HttpOnly` flag whenever possible AND `Secure` flag when behind SSL

* Make sure the Database library uses PDO in its core

* Every service runs in UTC timezone (PHP, DB, OS etc). Offset calculations just for presentation or input (when explicitly necessary)

* Don't use $_POST and $_GET globals directly

* Support other methods (DELETE, PATCH, etc) by parsing the Request body properly

Personal tips:

* Use Composer

* Use Twig

* Use a nice Request/Response handler (Symfony2's HttpFoundation, for instance)

I am sure I forgot many things here, one day I compile a list with everything
I've been through.

Hope it helps!

:)

~~~
EvilTerran
_Don't use $_POST and $_GET globals directly_

May I ask why not?

~~~
krapp
If they aren't sanitized or validated they can generate exceptions or contain
malicious data which leads to XSS or SQL injection after they've been
reflected back to the user or added to a database. Since the values in these
arrays come from the user, they should always be considered actively hostile
and treated as such.

~~~
EvilTerran
Ah, gotcha. So, treat them like they're "tainted", in perl parlance.

I was thinking that remark was intended more along the lines of "never use
$_GET and $_POST directly, only ever access them via something like Symfony's
sfWebRequest::getGetParameter/getParameterHolder/etc", which struck me as a
bit overzealous as such rules go.

~~~
krapp
Yeah, just make sure _somewhere_ you're doing all the checking (type, length,
character set, providing sane defaults, etc.) that other languages probably do
for you.

Because users are evil and want to destroy you and PHP is only too happy to
help them... :\

~~~
EvilTerran
Yeah, I often feel like PHP is trying to destroy me.

/ used Haskell at uni, loved it

// first job in the real world is... web dev, on a sprawling legacy PHP
codebase, with no documentation or tests

/// I miss my static guarantees :(

------
UnoriginalGuy
> NEVER hash passwords with MD5/SHA-1/Hash-of-the-day

> PHPass will make life easy for yourself and keep your users' passwords
> secure.

MD5/3DES/SHA-1 are relatively broken. But saying "use this magical library" is
really far from a solution. Who's to say that that library won't be broken
tomorrow and then someone else won't write an article next week saying "don't
use PHPass!"

Programmers just need to stay up-to-date with the latest trends and adjust
their approaches accordingly.

> MD5/SHA-1/Hash-of-the-day is not, was not, and never will be acceptable.

MD5 was very much acceptable for the longest time. Back when everyone was
using 3DES, MD5 was seen as the Bcrypt of the time. So saying that it "never
was acceptable" is simply nonsense.

It was even what was implemented by the standard libraries and APIs of the
time.

~~~
chacham15
No.

>MD5 was very much acceptable for the longest time.

MD5 was never a good password hash. Neither is SHA1,256,etc. The reason is
that they are crypto hashes optimized for speed. This is bad for passwords.
What you should be using is the opposite: an expensive hash to compute. This
is bcrypt which has been in use since 1999 (and what the PHPass is based on).
This is a clear example of "Dont do your own crypto" because you dont know all
the details.

>It was even what was implemented by the standard libraries and APIs of the
time.

Yes, and this was a mistake. But to be fair DES used to take a full second to
compute and bcrypt wasnt invented until 1999. This is why current password
hashes use variable rounds so that we can increase the cost as computers get
faster. When the algorithm is DESIGNED to be computed quickly it is
fundamentally broken for passwords.

This is the reason that LinkedIn's passwords were vulnerable[1].

[1][http://www.itworld.com/security/280813/expert-calls-
linkedin...](http://www.itworld.com/security/280813/expert-calls-linkedins-
new-salted-hashes-useless)

~~~
UnoriginalGuy
> MD5 was never a good password hash. Neither is SHA1,256,etc. The reason is
> that they are crypto hashes optimized for speed.

That's strange to hear you say that, because I remember people having huge
arguments in the 1990s about how they couldn't use MD5 because it was /so/
slow and how 3DES was the only way to go!

I swear people love to re-write history.

> This is a clear example of "Dont do your own crypto" because you dont know
> all the details.

That doesn't even make any sense. MD5 is a standard cryptographic function. If
someone had used it they wouldn't be making their own crypto.

Hell, many of the standard libraries implemented MD5 when you asked them to
protect a password by default. That's so far from rolling your own it isn't
even logical to try and make the argument you're making.

Your entire post reads like someone who knows nothing about the history and is
just spouting "OMG USE bcrypt IT IS THE BESTEST AND WILL BE SECURE FOREVER!"

bcrypt too will fall from grace and then you'll have someone making a post
like yours saying "how could anyone use bcrypt, it is SOOO fast!"

~~~
rmrfrmrf
> "OMG USE bcrypt IT IS THE BESTEST AND WILL BE SECURE FOREVER!"

5000 people in a room all shouting this repeatedly -- pretty much how I
envision every Rails dev conference.

------
aarondf
Can someone help me understand why a "helpers" or "utilities" file of
functions is so bad?

Asking humbly because I do that and don't yet understand why it's bad / the
alternative.

~~~
rmrfrmrf
Helper files are a pain in the ass because they're usually all jumbled up and
hard to maintain. In my experience with them, they come a zillion functions
that are all unrelated, from input sanitization to XML processing to database
initialization. Then, when you need to figure out what the hell is going on in
your code, you have to wade through a forest of garbage just to figure out
what the function is doing. God forbid you accidentally make a typo in ANOTHER
function while editing the one you wanted -- now you've just introduced
another bug without even realizing it.

Furthermore, in PHP, we devs are almost always using the same boilerplate over
and over again (getting user input, etc.), so why would we use a "helpers.php"
file when we instead could break out our code into more semantic, reusable
chunks?

Instead, you should be creating classes (or at the very least, creating files
that all have related functions, not just throwing all of your "helpers" into
one file, so instead of helpers.php, you have inputSanitizer.php,
htmlParser.php, et cetera).

For example, I see a lot of this kind of thing in "helper.php" files:

    
    
        function sanitizeInput($input) {
            $input = htmlentities($input);
            ...
            return $input
        }
    

What I personally _love_ to do because I'm OO obsessed is use a home-grown
InputSanitizer class, so now when I have a new project, I don't have to copy
over my "helpers.php" file and then strip out everything unrelated to my
project; I just copy over InputSanitizer.php to the new project and do
something like this:

    
    
        $username = InputSanitizer::getPostData('username');
    

MUCH cleaner and easier to maintain. Even better: if you're using classes and
auto-loading, you'll never have to worry about includes again, you simply just
call the class methods or instantiate.

There's a clean, wonderful side to PHP that I think a lot of people aren't
taking advantage of.

~~~
tabbyjabby
I'd just like to note that that is not a particularly OO solution. You've
essentially created a namespaced function. While this is still preferable to a
bare function in a heterogenous helpers function file, it's certainly not a
pure OO way of accomplishing the encapsulation of the InputSanitizer.

~~~
rmrfrmrf

       $username = InputSanitizer::getInstance()->getPostData('username');
    

There. Now it's OO ;P.

~~~
z92
I would rather use Java in that case.

~~~
rmrfrmrf
Your wish is my command.

    
    
        $username = array();
        exec('java sanitize.class ' . escapeshellarg($_POST['username']), $username);

------
nikic
> PHP version 5.5 (not yet released) will support Bcrypt natively via its
> password_hash() function. Use it.

This makes it sound like PHP didn't support bcrypt before 5.5. It did. PHP
always has bcrypt support in 5.3 and 5.4. In older versions it also has bcrypt
support if the operating system supports it.

PHP 5.5 only added a wrapper around the low-level crypt() API, which makes
password hashes more convenient to use and less prone to error.

~~~
jcampbell1
The php 5.5 functions are really nice. Fortunately they can be shimmed into
versions 5.3.7+. See:

<https://github.com/ircmaxell/password_compat>

------
Piskvorrr
As for #6, I'd go as far as "NEVER use include, period." I've seen about 1
actual use case out of the bazillions out there; almost certainly, _require()_
is the droid you're looking for.

I'd also add a #10: Use E_ALL | E_STRICT , and don't ignore it. PHP is trying
to tell you of many problems, shutting it up is not the right answer.

~~~
SkippyZA
Couldn't agree more with E_ALL|E_STRICT.

The current legacy system I am maintaining took me 2 weeks to clear up 90% of
the NOTICE errors for using undefined variables etc.

Dirty code is dirty, and it is because of this that PHP has received so much
negative publicity.

~~~
jacquesm
The completely brain dead naming conventions for function names (or rather,
the lack thereof) is another. PHP has grown organically, just like the web, to
fill a very irregular shaped niche and it shows that history in all the gory
little details. That said it made me more money than any other programming
language combined (including C, but it's a very close second).

Probably a lot of people have similar feelings towards Ruby, getting stuff
done is what pays the bills.

~~~
Luyt
Quick! Was it ($haystack, $needle) or ($needle, $haystack) ?

~~~
jacquesm
Or better still... one where it doesn't matter:

<http://www.php.net/manual/en/function.implode.php>

------
acabal
For anyone interested in taking the next step for some of these suggestions
(i.e., "OK, never put variables in SQL, what do I do instead then?"): I
maintain <https://phpbestpractices.org>, which is an attempt to document the
"best" solutions to common low-level tasks, like DB access, which have lots of
possible dangerous approaches.

(Note I only talk about the version of PHP that ships with Ubuntu 12.04 LTS,
so brand-spanking-new stuff like password_hash() isn't in there.)

------
mikedwebdev
I have to disagree with your "Never use Ubuntu" way of doing things found
here: <http://biasedphp.com/windows-linux-distribution>

Ubuntu's focus on the newest and latest is primarily on the desktop not the
server. Better yet recommend user stick to LTS releases with 5 years of
support.

------
jtreminio
This whole thing could be replaced with the far better
<http://www.phptherightway.com/>

------
citricsquid

        8. NEVER create a file of useful functions, even if it's called helpers.php    
        This smacks of such a broken thinking process, it makes my teeth itch.
    
        If you have commonly-used functions, they should be integrated with 
        the commonly-used parts of your code.
    

Example function used for debugging:

    
    
        function preint_r($arr) {
            echo '<pre>';
            print_r($arr);
            echo '</pre>';
        }
    

Where would something like this fit, if not a general helpers.php type file?

~~~
bru
>Where would something like this fit, if not a general helpers.php type file?

In debugging.php alongside with other debugging helpers?

~~~
grobolom
Maybe if it's used solely for debugging, but there are cases where simple
functions aren't easy to place. Consider implementing the array_column
function for pre-5.4 PHP. Or things like method pull, index grouping, or
array_select_keys functions.

What helper library should a function like the following exist in?

    
    
      function array_select_keys(array $dict, array $keys)
      {
          $result = array();
          foreach ($keys as $key) {
              if (array_key_exists($key, $dict)) {
                  $result[$key] = $dict[$key];
              }
          }
          return $result;
      }

~~~
kijin
I have a similar dilemma with some of my helper functions. For example, I have
starts_with(), ends_with(), and contains() for super easy string comparisons,
is_between() for numerical comparisons, and custom implementations for a few
built-in functions such as hex2bin() that don't exist in older versions. These
are so general in scope that it would be awkward to place them in their own
\Namespace\Class.

~~~
rmrfrmrf
I'd probably break them all down into classes based on function (EasyString,
EasyNumber, BuiltIn).

    
    
        namespace App\Library;
        class EasyString {
            public static function starts_with();
            ...
        }
    

and then just use them like this:

    
    
        use App\Library\EasyString as ES;
    

along with an autoloader.

------
krapp
#1 oh, god yes. Variable variables and extract. I hate extract. Although i've
only actually seen it in production in wordpress... Though i'd edit this to
_always do the simplest thing that will work properly._ After all, the
simplest way to do a SQL query in php that works is to just dump POST vars
into a mysql function...

#2 I've actually gotten into an argument with someone who insists md5 is
perfectly fine for password hashing if you salt it. Better, in fact, because
it's faster. So yeah.

#3 Unfortunately we're also stuck with a ton of legacy code that does this,
and would be all but impossible to refactor, and i'm still pointing out to
people who post code like this to at the very least sanitize their stuff.

Seriously, if it's even possible, someone come up with an easy way to convert
old-style linear SQL statements to parameterized queries or something in PHP.

#4 HTMLPurifier is good, but can be incredibly slow. htmlspecialchars is
probably good where you don't need to sanitize data but still provide markup.
I personally use htmlpurifier after a markup generator like Markdown, so I can
enforce a whitelist against it. Still, YMMV but do SOMETHING.

#5 Might as well say don't use Wordpress either. I have yet to find a
framework that makes me as angry as it does. Though granted, I haven't
actually used cakePHP yet and I hear Zend Framework is a bit gnarly. Though
"Use a framework when you can" is probably a good rule. Though eventually that
ends up being "don't reinvent the wheel"

#6 WHO EVEN DOES THIS?!

#7 I don't know. Depending on how many you're sending, it's probably fine for
low volume. It's probably right though.

#8 Don't really agree with this at all. In a global file, the body of
helpful_function() is in one place, so if I want to change it or upgrade it,
it's right there. If I integrate it into the rest of my code, I have to go
look for it or else deal with multiple definitions in different files.

Though I will agree that if you're only using a helper function _once_ in your
code, then clearly it needs to be integrated somewhere else. My definition for
a helper function is that it gets used multiple times in no particular place.

#9 Most php developers work with whatever server their host is using, so this
is of limited utility.

------
chrisguitarguy
I would recommend Doctrine DBAL[0] over Meekro.

0\. <http://www.doctrine-project.org/projects/dbal.html>

------
Jleagle
Wow, this guy really hates CakePHP. If you know what you're doing and don't
just presume Cake has done it for you, none of those problems should exist.

~~~
TheCapn
I find that to be very true. Seems a lot of amateur programmers pick up
CakePHP for one reason or another without actually knowing PHP and try to
drive every screw with the one hammer they have. When everything's suddenly
broken they blame the hammer.

EDIT: Although I suppose the author's point of view is from the outside-in
where he's tasked with cleaning up the mess that amateurs leave behind and has
a bias against it.

~~~
Schlaefer
If you know what you're doing you will not pass around huge arrays (in PHP) by
value. Or pass them around (in CakePHP) at all, it's maybe a MVC warning flag
that you do something in a place you shouldn't.

Related note: CakePHP 3.0 (current is 2.x) will use objects [1].

[1] [https://groups.google.com/d/msg/cake-
php/-TLn6RpHt4U/EAP0lt2...](https://groups.google.com/d/msg/cake-
php/-TLn6RpHt4U/EAP0lt2yjsAJ)

------
shousper
The more of these posts I read, the more I believe most PHP programmers (as a
majority) really aren't "clean coders" or have any intention of writing
organised, maintainable. More likely they are just coders who write what they
have to, whatever works and takes the least amount of time to get the job
done.

A sweatshop language? Haha, no I take that back, it's not like that..

~~~
krapp
Yes, and Ruby on Rails users are just hipster kids who consider installing
modules to be 'coding'.

Herp, and if I might be so bold, derp as well.

------
martin_
Few comments..

#3 assumes that the variable came from user input, it's not necessarily bad.
In some cases (i.e. dynamically switching from ORDER BY ASC/DESC) it's quite
acceptable. But PDO + prepared statements for sure.

#4 no need to use a library, htmlspecialchars/htmlentities are quite enough.

#5 I think many frameworks/libraries can go here - why pick on one?

#7 Mailgun, sengrid etc are becoming increasingly popular - worth mentioning.

#9 isn't PHP related

I agree with Piskvorrr - I favor require (though it isn't a function, no need
for parenthesis.)

~~~
astrodust
#3 should be #1, and further, it should read "If you insist on writing your
own database layer, stop. You'll do it wrong in the worst possible way."

PHP has institutionalized SQL value injection. mysql_query cannot be removed
soon enough.

~~~
martin_
#3 should be #3 :)

> mysql_query cannot be removed soon enough.

I agree. Bring on 5.5

------
mattacular
I agree with most of these except the one about helper functions but I think
it was just written poorly (like the whole article). Definitely sort your
functions into the files where they are most applicable, but sometimes (a lot
of the time) you will have toolkit/helper functions which are globally
applicable to the entire app. Where should those go? A helper or toolkit PHP
file IMHO.

------
jcampbell1
Is sending email really that slow? In my experience, it just writes something
to a local mail queue if your front ends can send email.

~~~
UnoriginalGuy
It can be that slow, yes. There is no assurances that will be fast, you're
just hoping it will be.

Now you could argue "that's true of anything!" but in general you are forced
to depend on local IO/CPU/RAM otherwise your site is struggling in general, by
adding DNS/SMTP/etc you're just adding more "stuff" that your site relies
upon.

Plus SMTP servers are "allowed" to go offline for short periods. The client
should try to resend the email 2-4 additional times before giving up. Clearly
a PHP script cannot do that.

~~~
jcampbell1
I am totally confused. Who uses an SMTP server written in PHP? mail() just
writes a bit of stuff into a mail queue by default.

~~~
UnoriginalGuy
People set their PHP config to connect to a remote SMTP server rather than a
local queue.

It isn't something you can control in the code.

~~~
jcampbell1
Thanks, I understand. Configuring PHP that way would be an unmitigated
disaster. If you want that functionality, it makes the most sense to configure
Exim or whatever to do that for you.

------
martin_
The comments pretty much sum up how useful this blog post is... The upvotes
merely show how educated a lot of the PHP community isn't

~~~
ihsw
"The PHP Community" comprises massive swaths of developers, from people who
have a hard time caring about things like "namespaces" and "encapsulation" to
people who think and breath those concepts on a daily basis. It would be
disingenuous to make such broad-sweeping and baseless statements about the
entirety of a group of people.

Please don't get confused and paint everybody so broadly, it damages us all.
There are many people working hard to improve the language and create a more
modern environment around PHP.

------
hjay
If you want to see why you should always use prepared statements in your code,
take a look at this [1]. Old and outdated, but still very much applicable.

[1]: [http://technewsgalore.com/site/04/15/sql-injection-
tutorial-...](http://technewsgalore.com/site/04/15/sql-injection-tutorial-by-
for3v3rforgott3n)

------
adamors
Are people still using PHP without frameworks these days?

~~~
heidar
The "cool kids" in PHP are using Laravel 4. It's a well made framework. I'm
doing a REST API in it at work and the lack of mind share and docs is probably
the worst part about it (it's still in beta to be fair). Most of the time I
ended up reading the framework code.

PHP leaves a lot to be desired though. It boggles my mind how developers who
love what they do have the patience to stick with it. Example: Feature request
for the unless control structure: <https://bugs.php.net/bug.php?id=40296>

~~~
krapp
Is anyone using Laravel 4 in production already? I thought it was still in
beta.... I'm still messing with 3.

~~~
heidar
I've seen a few people doing it. The API is quite stable since the end of last
year or so I've heard. I didn't start using it until recently and I haven't
encountered any bugs and whenever I gear up to do a pull request someone else
has already done it.

~~~
krapp
ooh, neat. I'll have to start on that then.

------
pieterp
#6 re: autoloading. PSR-0?

------
alekseyk
Most of the items on that list are not specific to PHP.

Some of the stuff pointed out is up for discussion (I hate when people use the
word 'NEVER' when they are writing about their point of view, especially when
programming is a topic).

------
rmrfrmrf
_These_ are the "PHP Commandments"? How about we set the bar a little higher?
Anyone who has had longer than 1 day's worth of training with PHP should know
these things.

~~~
Piskvorrr
_Should_ is the operative word. I keep being amazed at what people _ought to_
know, yet _don't_.

