PHP Commandments
biasedphp.com
biasedphp.com
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).
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!
:)
May I ask why not?
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.
Because users are evil and want to destroy you and PHP is only too happy to help them... :\
/ 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 :(
> 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.
>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...
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!"
5000 people in a room all shouting this repeatedly -- pretty much how I envision every Rails dev conference.
(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.)
> 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.
Asking humbly because I do that and don't yet understand why it's bad / the alternative.
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.
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.
$username = InputSanitizer::getInstance()->getPostData('username');
There. Now it's OO ;P. $username = array();
exec('java sanitize.class ' . escapeshellarg($_POST['username']), $username);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.
I'm the one saying that strict OO is bad because it's verbose and its slower than the alternative.
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.
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.
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.
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.
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.
Probably a lot of people have similar feelings towards Ruby, getting stuff done is what pays the bills.
The reason this works is because -1 is 0xFFFFFFFF.
(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.)
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.
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?In debugging.php alongside with other debugging helpers?
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;
} 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
http://php.net/manual/en/function.array-intersect-key.php $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.
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.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 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?
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.
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.
#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.
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.
Related note: CakePHP 3.0 (current is 2.x) will use objects [1].
[1] https://groups.google.com/d/msg/cake-php/-TLn6RpHt4U/EAP0lt2...
A sweatshop language? Haha, no I take that back, it's not like that..
Herp, and if I might be so bold, derp as well.
#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.)
PHP has institutionalized SQL value injection. mysql_query cannot be removed soon enough.
> mysql_query cannot be removed soon enough.
I agree. Bring on 5.5
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."
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.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
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.
It isn't something you can control in the code.
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.
[1]: http://technewsgalore.com/site/04/15/sql-injection-tutorial-...
Couldn't help myself :(
(who were a bit upset when they looked for jobs elsewhere)
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
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.
(Haskell even does it as a function, and not as a macro.)
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 ...
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.
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).