Command Injection vulnerabilities are extremely dangerous, often easy to exploit, and give attackers the ability to execute operating system commands with the privileges of the web application user. These properties allow Command Injection to be scaled up to build botnets, so it is very important to take measures to prevent such vulnerabilities. Fortunately, it is fairly simple to prevent Command Injection vulnerabilities once you know how to do it. Two techniques you can leverage to prevent them are to avoid using operating system commands from within the application and using parameterized APIs when it is absolutely necessary to execute operating system commands.
To identify potential trouble spots, create a spreadsheet of all the code in your application that executes operating system commands. This code can be found by searching for the use of the following functions: exec, passthru, shell_exec, system, proc_open, popen, curl_exec, curl_multi_exec, pcntl_exec, dl. With the spreadsheet of potentially dangerous code in hand, examine each piece of code that executes operating system commands and determine whether it is absolutely necessary to the application. If possible, rewrite that code to use only PHP functions, thus removing the possibility that it contains a Command Injection vulnerability.
If application functionality requires executing operating system commands, this should be done using parameterized APIs. In PHP this is done using the pcntl_exec function (the reference for this function is available at http://php.net/manual/en/function.pcntl-exec.php). The pcntl_exec function is the safest command execution function in PHP, but it has some drawbacks and should still be used with care. One of the main drawbacks of the pcntl_exec function is that it doesn't return the output of the executed process. However, the executed program is not executed via a shell, so it is very hard to trick pcntl_exec into executing a program other than the one that is intended. Arguments passed to the program being executed are passed via a separate variable from the path of the program - this is the "parameterization" part. Because the arguments are passed in a separate variable, the arguments cannot be manipulated into causing PHP to execute some other application in typical scenarios. It is possible to craft a scenario where pcntl_exec is used to execute a shell and pass it the name of some other command as the argument, but that is ill-advised. Better yet, just don't do that!
The correct way to use pcntl_exec is to not allow the user to supply the path of the program to execute; rather, supply a full path to the program that needs to be executed, and make sure that the program being executed cannot execute any other programs based on the arguments that it receives. The path of the program to execute can usually be determined without any user input and that should be done. The user should never be allowed to arbitrarily decide what program to run - that is the primary attribute of a Command Injection vulnerability. If it is absolutely necessary to choose what program to run based on user input, define a list of allowed and safe programs to run, place the paths to these programs in an array, and then choose the index of the array based on the user input to correspond to the program that needs to be executed based on the user's choice. All paths passed to pcntl_exec should be fully qualified paths from the file-system root. I recommend using the realpath function to determine the fully qualified path of the program to run. Most of the time, if user data is needed for executing an external program, it is passed in the arguments to the application. Most user data should be safe to pass to external programs using pcntl_exec, however it is important to consider whether the external command itself can potentially be abused. One particular issue to watch out for is whether the external program can execute other programs based on the arguments that are sent to it – an obvious example is passing arguments to a shell. For most practical scenarios, this should not be an issue, but it's something to be aware of.
Armed with the understanding of how to execute external commands safely using pcntl_exec, all code that uses other PHP functions for executing external commands should be replaced. Be sure to go through your spreadsheet of code that executes external programs and rewrite each piece of code to use pnctl_exec. Once this is done, you will have taken effective measures to prevent Command Injection vulnerabilities in your PHP application.