Hacker News new | past | comments | ask | show | jobs | submit login
PHP Commandments (biasedphp.com)
57 points by mootothemax on April 30, 2013 | hide | past | favorite | 110 comments



> 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).


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!

:)


Another nice Request/Response handler is Guzzle[1], which is what Amazon's AWS-API library uses. Guzzle's easy support of parallel HTTP requests is really nice.

[1] http://guzzlephp.org/


Don't use $_POST and $_GET globals directly

May I ask why not?


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.


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.


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... :\


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 :(


> 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.


You're right that today's algorithms or libraries might be broken at some distant point in the future, but I don't see how that would change today's recommendations. Today's best practices are the same regardless of what will happen in ten years. When something better comes along, then people should move to that; until then, PHPass and bcrypt are reasonable suggestions.

> But saying "use this magical library" is really far from a solution.

PHPass is managed by OpenWall. They're some pretty smart people. The only niggle I can think of with PHPass is that they read from /dev/urandom without trying /dev/random; theoretically /dev/urandom is unsuitable for cryptographic applications, but using /dev/random is tricky and error-prone, especially in VPS environments. (You can install haveged on Debian to feed /dev/random if you're interested in that sort of thing.)

Given the choice between using OpenWall's PHPass bcrypt implementation or rolling my own, I'd use theirs without a doubt.

What alternative would you suggest?

> 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.

True, but sort of pointless. My best recollection is that MD5 was last considered OK back in 1997 or thereabouts, but I might have early-onset alzheimer's or something.


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...


> 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!"


You obviously have no idea how bcrypt works; go search for "bcrypt work factor". In other words, making bcrypt slower while remaining secure is a matter of changing the work factor.

(This doesn't preclude bcrypt falling from grace for having - as of yet undiscovered - other security flaws; but it is designed with Moore's Law in mind. Saying "I don't know why everyone praises bcrypt, but HEY LOOK AT ME REBELLING, BCRYPT SUXXORZ!" is not very effective.)


> "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.


MD5 for password storage isn't broken. It's still incomparably better than encrypting passwords. The problem is that it requires you to have a very strong password to start out with. This is 'acceptable' in that the security works with MD5, but 'unacceptable' in that it makes security much harder than it should be for no benefit. And it has always been this way, regardless of what people have thought about it in the past. That's the benefit of hindsight. Nothing has actually changed MD5's security. Finding a broken library is a completely different and more easily fixed issue.


Hashcat can do 5 billion md5 hashes per second on a single gpu. Even difficult passwords are crackable in md5.


Adding six lowercase characters/numbers increases the difficulty by a factor of a billion. So if you look at a typical 8 character rule and go up to 14 random characters you're perfectly safe on md5.


...which, sadly, will lead to a proliferation of yellow stickies. Depending on the physical security of the individual workstation, this may not necessarily be a bad thing (but in the most common case "anyone has physical access" probably will be)


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.


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.


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.


This is a problem that goes all the way to the core. It isn't very good OO (some will argue PHP isn't really OO anyway) because core types are not objects. Whether you have substr(..., ...), Helper::substr(..., ...) or getSomeInstance()->substr(..., ...) it's really all the same, with maybe some added benefits if you provide some wrapper functionality as in the last case.


   $username = InputSanitizer::getInstance()->getPostData('username');
There. Now it's OO ;P.


I would rather use Java in that case.


Your wish is my command.

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


And very fortunately so. 'Pure' OO is the madness that created Java.

Encapsulation is overrated. So overrated that you need another fancy concept like 'dependency injection' when it just gets in the way.

The static function is simple and because of that, it is good.


tabbyjabby didn't say it's bad. They just said it's not OO.


I know. It implies the assumption that not complying with OO is something code should avoid as a rule of thumb.

I'm the one saying that strict OO is bad because it's verbose and its slower than the alternative.


I think it more implies that object oriented things should be called OO and not-object-oriented things should be called something that isn't OO.


Count me in as saying that not only strict OO is bad, but OO is a bad idea in general. At least in its usual form. You might manage to tackle something OO-like on, say, FP, and get away with it.


This definitely isn't limited to PHP. While there may be instances where 'helpers.xyz' is OK, they're very, very few and far between. When you create a file like that, you've conceded defeat at actually naming things usefully.

If 'logging.php' or something similar doesn't fit what you're doing, and it doesn't fit well with anything else in your project, and there's no other way that would fit in with something intrinsic to your app, then this might be OK. But that's kind of hard to fathom.

In my opinion, though -- while I agree that it's something to be avoided at many costs -- the real problem with this, as with many things, is overuse. I'm on at least one project right now where the unconscionable overuse of helper functions (an entire directory of them with questionable file names, actually) has turned a Django project into horrible spaghetti code.

It's definitely not an isolated incident. In all languages, if what you're doing has any kind of logical structure, it's worth taking pains to make sure things go in logical places. You'll thank yourself in the future, and so will your successors.


Since you can't autoload functions who aren't members of a class, you must include/require the file on every request, or otherwise include the file whenever you use those methods. PHP projects have, generally, abstracted the thinking about "what file does this thing come from?" by now - via the autoloader - which, as I said, doesn't work with functions. So functions, annoyingly, create a leak in the abstraction that otherwise allows us to forget about exactly what files our code lives in.

As an aside, to me, it also raises questions regarding the design of your code (how do I inject mock methods?). But that's hard to know without seeing it (if the methods are simple enough, perhaps there's just no need to mock them in your tests).

I encapsulate "helper" or "utility" logic in objects, e.g. RandomGenerator with a getRandom, which can be amazing when it comes to testing, and lets me forget about include/require'ing files.


It isn't - they should be abstracted to what they help with though. For example I have a \Helpers namespace and my autoloader brings them in as required: http://pastie.org/7743301


I don't quite agree with him on that also.

PHP is multi-paradigm, if you keep helpers functions in a way it's well structured and feels right in your project, why do not use them?

This is a personal preference, not a fact.


there's no generic "helpers". probably he meant to be more specific like htmlparsinghelper.


> 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.


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


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.


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.


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.


I haven't seen anywhere near the same level of hate for Ruby - and I can't help thinking it's because PHP is objectively worse. A lot of the problems listed in the article wouldn't arise in a language with a better module system (such as Ruby), for example.


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


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

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


Even better, set error reporting to -1. This will catch every error, even if PHP devs decide to add a new type of error that isn't included in E_ALL | E_STRICT. (They already made E_STRICT not part of E_ALL, so there's no guarantee they won't do it again.)

The reason this works is because -1 is 0xFFFFFFFF.


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.)


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.


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


    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?


You should install xdebug, and then var_dump will do what you want and a lot more.


Isn't that just letting someone else write your helpers.php?


No, it's moving debugging into a discrete, well-understood debugging package (Xdebug) rather than jumbling it together with a bunch of unrelated stuff in a big grab bag labeled "Miscellaneous".


I agree. Also, 8. (no helper functions) contradicts 1. (do the simplest thing).


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

In debugging.php alongside with other debugging helpers?


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;
  }


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.


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.



array_intersect_key does not do the same as array_select_keys. You can emulate it using array_intersect_key, but either in a more confusing or slow way.

  $array = ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4];

  array_select_keys($array, ['a', 'b']);
  array_intersect_key($array, ['a' => '', 'b' => '']); // OR
  array_intersect_key($array, array_flip(['a', 'b'])); // OR
Neither are elegant.

In either case, that wasn't the point. This is a basic kind of functionality that doesn't belong to any particular class in most code bases. So in this case, having a class of 'helper' functions like these isn't bad.


array_intersect_key([], array_flip([])); is pretty idiomatic actually lol, but that's PHP for you.

The point still stands, though, that you shouldn't put array_select_keys into a php file filled with other helper functions. array_select_keys would go perfectly into a helper class called ArrayHelper with a bunch of other array convenience functions.

I'm pretty sure the author was talking about a helpers.php file like this:

    myGetPlaintextUserPasswordFromGET();
    encryptPasswordMD5(); //don't use this one anymore
    connect_to_my_mysql_database(); //complete with hardcoded values
    increment_for_loop();
    my_input_sanitizer();
    encryptPasswordSHA1(); //don't use thiS!!!
    my_improved_input_sanitizer(); //use this one from now on!!
    add_user_to_database();
    getCharacterAtPosition();
    generate_a_random_number_between_one_and_ten();
    show_user_alert();
    encryptPasswordSHA1_withsalt(); //USE THIS OnE!
    myConvertEmoticonToSmiley();
    ...
nightmarish.


The point still stands, though, that you shouldn't put array_select_keys into a php file filled with other helper functions.

It doesn't stand. There's absolutely nothing wrong with having a file with simple helper functions.

  ArrayHelpers::array_select_keys();
is in no way better than

  array_select_keys();
There is plenty wrong with the helpers file you described at the end of your post. But it's because those functions break basic programming principles, not the fact that they happen to be simple functions in a file (and most of them are not even simple).


ArrayHelpers::array_select_keys() makes it obvious that array_select_keys() is a user defined function.

ArrayHelpers helps me never wonder about where to find an array convenience function. ("array_select_keys() must be in the ArrayHelpers class" vs. "Hmm...where is that function...ugh ok let me run a find on it...oh there it is, right in between create_html_tag() and get_primes()").

ArrayHelpers lets me do lazy loading, so instead of loading everything from encrypt_password() to get_cookie_val() to do a simple task, I only get some useful array functions. Related to that, ArrayHelpers adheres to the interface segregation principle, so my function that I'm using array_select_keys() with doesn't have to know about functions that don't apply to it.

AutoHelpers helps keep my files small and maintainable. You know we've all seen helper.php files that are so monolithic that they have to be broken up with separators like this:

    ////////////////////////////////////////
    //
    //       -- ARRAY FUNCTIONS --
    //           lol oop suxx
    //
    ////////////////////////////////////////
Just to make them somewhat readable. I mean, come on, you know you've seen that.

ArrayHelpers lets me avoid obnoxious require() statements.

ArrayHelpers can be used on pretty much every future project ever without modification, so I know it will work out of the box. helpers.php on the other hand? Well, oh crap, some app-specific helpers just happened to weasel their way in there, guess I better delete them. OOPS! Deleted a semi colon by mistake and now my whole app has borked itself.

I mean, what's not to like? A few extra characters?


You know we've all seen helper.php files that are so monolithic

Yes. This has nothing to do with flat functions vs. classes. I've seen 'helper' classes get shitted up just as much as function files.

My point is that it doesn't matter. Many projects don't require heavy portability, and in either case, bootstrapping a namespaced shim next to your autoloader isn't a problem.

I'm not arguing that if you have a very extensive functions library, you should separate it out. I totally agree that you should. But saying 'NEVER MAKE A FUNCTIONS FILE NEVER EVER EVER ON PAIN OF DEATH' is silly.


Never ever write your code to the taste of some random other person who wouldn't contribute anyway, that's my motto...


Isn't that just making multiple helper files? Which is better, five files each with one function or one file with five?


IMO that should be a method on a Logger object. Personally I have a method that does a similar thing called 'inspect'.

Even better: you should write to a log file instead of to the screen (at debug level) for such things so you don't have to remove your (useful) debug statements before committing.


I agree, theres nothing wrong with having some global functions in a file.


#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.


I would recommend Doctrine DBAL[0] over Meekro.

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


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.


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.


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...


I have no brief for or against Cake (never used it myself), but input filtering seems like exactly the sort of tedious-but-necessary infrastructure code that a good framework is supposed to let you avoid having to write from scratch for each new project. If Cake doesn't do that, I don't think it's unreasonable to count that as a strike against it.


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..


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.


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.)


#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.


#3 should be #3 :)

> mysql_query cannot be removed soon enough.

I agree. Bring on 5.5


I don't favor require, I require it (sorry for the pun).

The main issue is that include() will just emit a warning and continue if the file doesn't exist, often leading to a confusing fatal error in a completely different part of the code; in other words, On Error Continue Next, PHP version. Even worse, people who use include are even more likely to use @include().

Oh, and require_once(), while we're on the subject: "if you're purposefully trying to require() a file twice, you're doing something Very Wrong."


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.


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.


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.


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.


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.


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.


Yes it's slow in that it's a blocking call. Since it takes more than a fraction of a second put a message in the mail queue, it'll _feel_ slow.


I am trying to verify your claim:

    php -r '$s = microtime(1);mail("jcampbell1@gmail.com","test","text");printf("%d\n ms",(microtime(1)-$s)*1000);'
    > 20 ms
20 ms doesn't _feel_ slow. You spend far more time fetching the data and rendering the email.


Just realized I edited out (before I posted) my qualifcation for my statement, but it should've been prefaced as "from what I've noticed with no hard numbers."

The reason I assume that it has the feeling of being slow, from the applications I've had to clean up, is because many times there's processing happening right before the mail() function. So while, yes, its relatively fast the the total time is what feels slow.

And for comparison I've ran your commandline test as well with two of my cheap-o VPS instances, one of which is a Linode instance:

Linode: 50ms, 13ms, 14ms

Crappier VPS: 677ms, 149ms, 188ms


Yeah that one caught my eye in an otherwise good list too. Typically sending email via PHP's mail() function is only slow if your server is not configured correctly: http://www.alphadevx.com/a/372-Fixing-slow-performance-of-se...


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


"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.


Right, which is why the Ruby and Python threads just tend to get ignored -- because everyone in those communities already knows everything about everything... (especially PHP)


Or just up front and honest. Which leads to open discussion. Which improves things. Maybe...


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-...


Are people still using PHP without frameworks these days?


The most painful thing about the years I spent working with PHP was having not even understood that web development frameworks existed. The little slice of the development world I existed in had absolutely no exposure to the concept... after switching to Python and only then discovering the concept, most of those PHP memories, in addition to being painful, became simultaneously embarrassing.


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


Just to be smug: In Haskell and Lisp you can add those control structures yourself in your source code (without having to hack up the compiler).

(Haskell even does it as a function, and not as a macro.)


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


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.


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


I'm curious, why did you choose Laravel over Symfony?


We used Symfony 2 on projects previously. I find that it makes simple things hard to do and it is too verbose.

Laravel 4 uses many of the Symfony 2 components but makes nice facades that you can call as static methods so you never have to worry about namespace importing and it makes things a lot less verbose and easy to use.


I don't use frameworks with PHP. I build as I go, but it's always purpose-built.

I confess that I don't get the point of PHP frameworks: PHP is a framework; I've never needed to do more than tweak it a little to fit my personal style. For example, I have a "DBI" class file that's all of 133 lines (including tags & comments) that's a light wrapper around PDO, with some error logging & management and an easy iterator over result sets. It does everything I need for databases; I genuinely can't imagine needing anything more complex.

My html library is a little bigger -- 1200ish lines currently -- but that's largely because I implemented bits of jQuery into PHP ...


If it's a project you never expect anyone else to pick up then that's probably fine... but frameworks make extending, maintaining and updating projects better by keeping code organized and concerns separated, assuming multiple developers will be working with it over a long period of time.

Like mixing jquery (or any js) into PHP... perfectly valid and probably close to what it was actually meant to do, but with a framework (on top of PHP) you might have an asset loader to manage scripts and dependencies or put the script tags into view templates to keep the markup separate from the logic. In a few years if someone has to come in and maintain your code, they might be familiar with it in the context of a framework, versus having to parse everything mixed in together. Something like changing the ORM or changing the template handler becomes much easier because the framework provides that extra level of abstraction.

They also attempt to create organized and universal solutions for general use-cases, so that with minimal effort using the same framework and tools you could make any number of CRUD apps. For a lot of people it's worth the complexity to not have to deal with the overhead of picking and installing libraries or writing an ORM of their own, probably very similar to the "convention over configuration" idiom in RoR. Sometimes the price you pay for this is configurability and speed.


Let me introduce you to my colleagues.

(who were a bit upset when they looked for jobs elsewhere)


Are people still using PHP these days?

Couldn't help myself :(


#6 re: autoloading. PSR-0?


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).


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.


Should is the operative word. I keep being amazed at what people ought to know, yet don't.




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

Search: