Mastering PHP Design Patterns
上QQ阅读APP看书,第一时间看更新

Not invented here syndrome

Cryptography can teach us a very important lesson about software; this is especially true about Kerckhoffs's principle. The principle states this:

"A cryptosystem should be secure even if everything about the system, except the key, is public knowledge."

This was reformulated by Claude Shannon in a form known as Shannon's Maxim:

"One ought to design systems under the assumption that the enemy will immediately gain full familiarity with them".

In layman's terms, in order to have a secure system, it shouldn't be secure just because no one knows how it's been implemented ("security through obscurity"). If you were to secure your money through obscurity, you'd bury it under a tree and hope no one would find it. Whereas, when you use a real security mechanism, such as putting your money in a safe in a bank, you can have every detail about the security system as public information, but providing the security system is truly secure, you would really only have to keep the key to the safe secret and every other detail could be public knowledge. If someone was to find the key to your safe, you only need change the combination, whereas if someone actually found where your money was buried under a tree, you would actually have to dig up the money and find somewhere else to put it.

Security that is only done through obscurity is a bad idea (that said, it's not always a bad idea). As you may be aware, when you store a password in a database you should use a one-way cryptographic algorithm known as a hashing algorithm to ensure that if the database is stolen no one can ever use the data in the database to find the user's original password. Of course, in reality, you shouldn't just hash a password, you should salt it and use an algorithm such as PBKDF2 or BCrypt, but this book isn't about password security.

The reality of the situation, however, is that sometimes, when developers actually do bother to hash passwords, they decide to create their own password hashing functions, functions that are easily reversible and are only secured by the obscurity of someone not knowing the algorithm. This is a perfect example of not invented here (NIH) syndrome; instead of a developer using a well-created password hashing library that is highly respected, they decide to create their own, pretending they are a cryptographer without understanding the security implications of such a decision.

Thankfully, PHP now makes it painlessly easy to hash your passwords; the password_hash function and password_verify function make this really easy with the password_needs_rehash function even telling you when the hash needs to be recalculated. Nevertheless, I digress.

So what actually is NIH syndrome? NIH syndrome is where a false sense of pride in an organization or individual developers own ability leads them to build their own solution instead of adopting superior third-party solutions. Reinventing the wheel isn't only costly, unnecessary, and can add needless overhead in maintenance; it can also be horribly insecure.

That said, where solutions are closed source and locked down, then it might be a good idea to avoid them. Doing so would also avoid vendor lock-in and restrictions on business flexibility.

NIH syndrome relies on the existing solutions being good and living up to expectations. Using third-party libraries is no excuse not to review their code quality.

Contributing to open source solutions is a great way to alleviate these issues. Room for improvement on an existing library? Fork it, propose an amendment to be merged in. No library that does the functionality you're after? Then you might want to consider writing your own library and publishing it.

I will finish this section by saying that the world has become heterogeneous; people are no longer looking for one technology stack to answer all their prayers; people are nowadays after the best tool for the job. It's worth thinking how you can utilize this fact for your own benefit.

Third-party dependencies with Composer

Composer makes it really easy to manage third-party dependencies. In Chapter 1,  Why "Good PHP Developer" Isn't an Oxymoron, I briefly described how you can use Composer for autoloading. Big deal, autoloading has been supported as a core function since PHP 5.1.2, but the great thing about Composer is that you can also use it for dependency management. Composer can effectively go and fetch the dependencies you need using the version constraints you specify.

Let's start off the with the following composer.json file:

{ 
  "autoload": { 
    "psr-4": { 
      "IcyApril\\ChapterOne": "src/" 
    } 
  } 
} 

So let's pull in a dependency:

{ 
  "autoload": { 
    "psr-4": { 
      "IcyApril\\ChapterOne": "src/" 
    } 
  }, 
  "require": { 
    "guzzlehttp/guzzle": "^6.1" 
  } 
} 

Note that all we've done is add a require parameter where we specify which software we want. No manually pasting files into your project or root, or using sub-modules in Git, for that matter!

In this case, we pulled in Guzzle, an HTTP library for PHP.

Composer by default queries repositories from a central repository called Packergist, which aggregates packages you can install from their various version control systems (such as GitHub, BitBucket, or another repository host). If you like, Packergist acts as a kind of phone book that connects the requests for packages from Composer to code repositories.

That said, it's not just Packergist repositories that Composer supports. In the spirit of being open source, it supports repositories from a range of VCS systems (such as Git/SVN) regardless of where they are hosted.

Let's take the following composer.json file:

{ 
  "autoload": { 
    "psr-4": { 
      "IcyApril\\ChapterTwo": "src/" 
    } 
  } 
} 

Let me demonstrate how you can include a repository from BitBucket without it being on Packergist:

{ 
  "autoload": { 
    "psr-4": { 
      "IcyApril\\ChapterOne": "src/" 
    } 
  }, 
  "require": { 
    "IcyApril/my-private-repo": "dev-master" 
  }, 
  "repositories": [ 
    { 
      "type": "vcs", 
      "url": "git@bitbucket.org:IcyApril/my-private-repo.git" 
    } 
  ] 
} 

It's that easy! You literally just specify the repository you want to pull in from and Composer does the rest. It's just as easy with other version control systems:

{ 
  "autoload": { 
    "psr-4": { 
      "IcyApril\\ChapterOne": "src/" 
    } 
  }, 
  "require": { 
    "IcyApril/myLibrary": "@dev" 
  }, 
  "repositories": [ 
    { 
      "type": "vcs", 
      "url": "http://svn.example.com/path/to/myLibrary" 
    } 
  ] 
} 

Rather cheekily, Composer can even support PEAR PHP repositories:

{ 
  "autoload": { 
    "psr-4": { 
      "IcyApril\\ChapterOne": "src/" 
    } 
  }, 
  "require": { 
    "pear-pear2.php.net/PEAR2_Text_Markdown": "*", 
    "pear-pear2/PEAR2_HTTP_Request": "*" 
  }, 
  "repositories": [ 
    { 
      "type": "pear", 
      "url": "https://pear2.php.net" 
    } 
  ] 
} 

In order to update the dependencies after you've made changes to your composer.json file, just run composer update.

Note that you can't update external dependencies using just composer dump-autoload. The reason for this is that dump-autoload will solely update the class map of your autoloader. It will essentially update the list of classes it needs to autoload; it won't go and pull in new dependencies.

Occasionally, when using Composer and pulling in dependencies, Git may say you need to generate a GitHub authentication key. This is because if you have Git installed on your local machine, Composer will go ahead and pull in dependencies by cloning then via a version control system; however, occasionally, if it's clinging repositories from GitHub, you might come up against its rate limit. If this happens there is no need to panic. Composer will give you instructions on how to actually go ahead and get an API key so you can proceed without rate limiting.

An easy way to get around this issue is simply to generate a local SSH key and then put your public key into your GitHub account. That way, when you clone from GitHub to your local machine you won't face any rate limitations and you won't need to bother setting up an API key either.

In order to generate an SSH key on a Linux/Mac OS X machine, you can just use run the ssh-keygen command, which will create a public and private key you can use for SSH authentication, including with Github or BitBucket. These keys will (usually) be stored in the ~/.ssh directory, noting the tilde (~ represents your home directory). Therefore, in order to get your key printed out into your Terminal window, run the cat ~/.ssh/id_rsa.pub command. Note that the .pub suffix indicates that id_rsa.pub is your public key that you can publically share. You must not share your private key, which is usually named just id_rsa. On Windows, you can use a GUI tool known as PuttyGen to generate public and private keys.

Once you've got your public and private keys, you can simply put them in GitHub by visiting the GitHub website and going to the SSH Keys page in the settings menu, paste in your key, and save it.

For subsequent updates, composer update will update to the latest versions of all dependencies as defined in composer.json. If you don't want to do this, though, there is an alternative; running Composer dump-autoload will solely regenerate the list of the PSR-0/PSR-4 classes that need to be included in the project (for example, you add, delete, or rename some of your classes).

Composer also supports private repositories, allowing you to effectively manage code reuse across multiple projects. Another key benefit is how Composer automatically generates a lock file that you can commit in with your projects. This allows you to effectively manage exactly which precise version of a dependency was installed at a particular point in time when you make a commit using your version control system.

Composer makes it easy and effective to manage third-party dependencies. Some crucial libraries are already available via Composer, such as PHPUnit, but there are also some other great libraries to make your life easier. Two of my favorite database libraries on Composer are Eloquent (a database ORM system from Laravel that you can find at illuminate/database) and Phinx (a database migration/seeding system that you can find at robmorgan/phinx). In addition to this, there are some great SDKs for various APIs that are available from Packergist (Google publishes some of its SDKs, and there are also some more specific ones, such as the Twilio SDK for sending SMS messages from your PHP app).

Composer allows you to specify dependencies for particular environments; suppose you only want to pull in PHPUnit on your development environments...that's not a problem!