Download the PHP package bamboohr/guardrail without Composer

On this page you can find all versions of the php package bamboohr/guardrail. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package guardrail

Guardrail - A PHP Static Analysis tool

Copyright (c) 2017-2024 BambooHR

Latest Stable Version Total Downloads Latest Unstable Version License composer.lock

Introduction

Guardrail is a static analysis engine for PHP 8.3. Guardrail will index your code base, learn every symbol, and then confirm that every file in the system uses those symbols in a way that makes sense. For example, if you have a function call to an undefined function, it will be found by Guardrail.

Guardrail is not proof that your code is perfect or even semantically valid. You should never use Guardrail as an excuse not to write unit tests. Rather, it is a final layer of protection to give confidence that preventable mistakes, syntax errors, or typos do not occur. You can think of Guardrail like the guardrails along a highway, you never want to hit one, but you're glad to know they are there.

At BambooHR we are big believers in continuous integration. We use Guardrail inside our open sourced CI tool, Rapid. (See https://github.com/BambooHR/rapid) This is done in addition to a healthy set of unit and integration tests that we also run against all layers of our stack.

Guardrail uses Nikita Popov's excellent PHP parser library. (See https://github.com/nikic/PHP-Parser)

The need for a tool like Guardrail in PHP

According to W3Techs (https://w3techs.com/technologies/overview/programming_language/all) in 2017 PHP is running on 82% of all the sites whose server-side language they can determine. Other documentation confirms that a vast majority of dynamic content on the Internet is served from PHP. PHP powers massive sites such as Facebook and Wikipedia.

Often these sites start from a small home grown code base, a Wordpress install, or a few customizations on top of a framework. These are great options that play to the strengths of PHP. You can quickly prop up a website and prove the business model before you spend a lot of time and money worrying about enterprise scale. The PHP language performs reasonably well and is very quick to develop with. The language is very forgiving, has a very mature library ecosystem with Composer, several robust frameworks, and broad hosting availability.

For a small website PHP works exceedingly well. If you are lucky enough to have a formerly small website that has grown up, you will start to run into difficulties dealing with large code base in PHP. Many of these complications are due to the fact that PHP is a weakly typed language. The lack of enforcements of contracts in the language makes it difficult to know what to expect about any given variable. On a small team and code base this is no problem. On a large team or large code base, this becomes unmanageable. Also, as your start to use more strongly typed improvements to PHP, you discover that those errrors are not reported until run time. It would be far better to know prior to release that errors existed in your application.

Guardrail is a tool that allows you to find some subset of the errors in your application. If you make heavy use of type hinting, you'll find that Guardrail enables you to actually be quite rigorous. It can be applied to any PHP 5 - PHP 7 code base.

Supported checks

Guardrail classifies checks by name. Here is the standard list of errors. Note that all Guardrail errors start with the word "Standard." Custom plugins, should begin with a different string. (Ideally, an organization name for the organization creating the plugin.)

Name Description
Standard.Access.Violation Accessing a protected/private variable in a context where you are not allowed to access them.
Standard.Autoload.Unsafe Code that executes any statements other than a class declaration.
Standard.ConditionalAssignment Assigning a variable in conditional expression of an if() statement.
Standard.Constructor.MissingCall Overriding a constructor without calling the parent constructor
Standard.Countable.Emptiness Use of empty() to check if a countable is empty or not
Standard.Debug Typical debug statements such as var_dump() or print_r()
Standard.Deprecated.Internal Call to an internal PHP function that is deprecated
Standard.Deprecated.User Call to a user function that has @deprecated in the docblock.
Standard.Exception.Base Catching the base \Exception class instead of something more specific.
Standard.Incorrect.ReadOnly Attempting to build an illegal readonly property (default value or non-typed)
Standard.Incorrect.Static Static reference to a dynamic variable/method
Standard.Incorrect.Dynamic Dynamic reference to a static variable/method
Standard.Inheritance.Unimplemented Class implementing an interface fails to implement on of it's methods.
Standard.Function.InsideFunction Declaring a function inside of another function. (Closures/lambdas are still allowed.)
Standard.Global.Expression Referencing $GLOBALS[ $expr ]
Standard.Global.String Referencing a global with either global $var or $GLOBALS['var']
Standard.Goto Any instance of a "goto" statement
Standard.Override.Base Attempt to use a #[Override] on method in a base class
Standard.Metrics.Complexity Any method/function with a cyclomatic complexity of 10 or greater.
Standard.Param.Count Failure to pass all the declared parameters to a function.
Standard.Param.Count.Excess Passing too many variables to a function (ignores variadic functions)
Standard.Param.Type Type mismatch on a parameter to a function
Standard.Parse.Error A parse error
Standard.Psr4 The namespace of the class must match in the final parts of the path with a ".php" on the end.
Standard.Return.Type Type mismatch on a return from a function
Standard.Scope Usage of parent:: or self:: when in a context where they are not available.
Standard.Security.Eval Code that runs eval() or create_function()
Standard.Security.Shell Code that runs a shell (exec, passthru, system, etc)
Standard.Security.Backtick The backtick operator
Standard.Switch.Break A switch case: statement that falls through (generally these are unintentional)
Standard.Switch.BreakMultiple A "continue #;" or "break #;" statement (where # is an integer)
Standard.Unknown.Callable A callable that can't be resolved into a class method or function.
Standard.Unknown.Class Reference to an undefined class
Standard.Unknown.Class.Constant Reference to an undefined constant inside of a class
Standard.Unknown.Class.Method Reference to an unknown class method
Standard.Unknown.Class.MethodString Occurrences of Foo::class."@bar" where Foo::bar doesn't exist.
Standard.Unknown.Function Reference to an unknown function
Standard.Unknown.Global.Constant Reference to an undefined global constant (define or const)
Standard.Unknown.Property Reference to a property that has not previously been declared
Standard.Unknown.Variable Reference to a variable that has not previously been assigned
Standard.Unsafe.Timezone Functions, such as date() that use a server setting for timezone instead of explicitly passing the timezone.
Standard.Unused.Variable A local variable is assigned but never read from.
Standard.Unreachable Code inside a block after a return, break, continue, etc.
Standard.VariableFunctionCall Call a method $foo() when $foo is a string. (Still ok if $foo is a callable)
Standard.VariableVariable Referencing a variable with $$var

Guardrail has support for advanced PHP features, such as traits, interfaces, anonymous functions & classes, etc.

Additionally, a simple plugin system exists that allows you to register node visitors for the abstract syntax tree for to enable additional checks. At BambooHR, we use this plugin mechanism to run some additional checks that are only relevant to our stack.

Limitations

Usage

There are two phases of execution in Guardrail: indexing and analysis.

Indexing

The indexing phase can only be run in a single process. A moderately large code base including all vendor libraries can take a few minutes to index.

Analysis

One the index is produced, the analysis can be run. Analysis is heavily CPU bound.
It can be run across multiple processes or even multiple machines. When run across multiple machines, you will need to gather the output from all of them to review the results. (BambooHR uses Rapid to automate this.)

Configuration

Guardrail configuration consists of 7 sections: options, index, ignore, test, test-ignore, emit, and plugins.

The options section is "optional". Currently it allows you to enable type inference based on DocBlocks. Often codebases will have a lot of DocBlocks that actually reference types that don't exist or aren't namespaced correctly. By default DocBlocks will not be used in type inference. If you enable DocBlocks then Guardrail can be much more exhaustive in what it checks. See the options section below for the options that can be defined.

The index section is a list of subdirectories to index. The ignore section is a list of file paths to ignore from indexing. The ignore section can use globbing patterns include double asterisks to indicate any number of directories.

These two sections work together to determine what files will be indexed.
Any file listed under an index directory, but not excluded by an ignore block will be indexed. It is important to index as much of your code base as possible because otherwise it will not be possible to resolve includes.

The test section is a list of directories to run the analysis phase on.
The test-ignore is a list of file paths to ignore from analysis. This section can also use globbing patterns to ignore multiple files at once.

The emit section is used to control which errors are reported. Most code bases will not pass with all of the standard checks emitted. We recommend adding a single check at a time and incrementally improving your codebase until all tests pass. If an emit string ends with "." then any rule matching everything before the final "." in the pattern is considered a match and will be output. Example: emit: ["Standard.Security.*"] to emit all security warnings.

The plugins section is a lot of plugins to use in the analysis. Plugins allow you to extend Guardrail with your own checks.

Sample config file:

The simplest version of an emit entry is a simple string that identifies the type of error to always emit. A longer form is a nested JSON object. It may contain a single glob string or array of glob strings that the filename must match and, optionally, an ignore string or array of strings to ignore. You may define multiple globbing rules per type of error.
If the error passes any one section it will be emitted.

You can also disable an error for the duration of a function by adding @guardrail-ignore [type1],[type2] in your function's docblock. (Where [type#] is the name of the check to disable.) Any check you disable will not be emitted during the analysis of that particular function.

Command line

Note: Command line usage will probably change significantly in the v1.0 release.

Usage: php -d memory_limit=500M vendor/bin/guardrail.php [-a] [-i] [-n #] [-o output_file_name] [-p #/#] config_file

where: -p #/#                               = Define the number of partitions and the current partition.
                                              Use for multiple hosts. Example: -p 1/4

       -n #                                 = number of child process to run.
                                              Use for multiple processes on a single host.  A good rule of thumb is 1 process per CPU core.

       -a                                   = run the "analyze" operation

       -i                                   = run the "index" operation.
                                              Defaults to yes if using in memory index.

       --diff patch_file                    = Allows you to limit results to only those errors occuring on
                                              lines in a particular patch set.  Requires unified diff format taken
                                              from the root directory of the project.  Must set emit { "when": "new" }
                                              for each error that you want to emit in this fashion.                                                                     

       --format format                      = Select choose between "xunit", "text", or "counts"                                 

       -s                                   = prefer sqlite index

       -m                                   = prefer in memory index (only available when -n=1 and -p=1/1)

       -o output_file_name                  = Output results in junit format to the specified filename

       --metric-output                      = Output results to the specified filename

       --symbol-table-output                = Output results to the specified filename

       -v                                   = Increase verbosity level.  Can be used once or twice.

       -h  or --help                        = Ignore all other options and show this page.

To index all according to the config.json file, storing the index in sqlite database, use the following command line.

php vendor/bin/guardrail.php -i -s config.json

To run the analysis

php vendor/bin/guardrail.php -a -s config.json

If you want to see progress during either the index or analysis phase use -v to enable verbose output.

By default, a report is output in Xunit format to standard out. If you would prefer to output to a file use -o to specify an output filename.

Incremental scanning

If you use the --diff patch_file option to Guardrail then you can filter your results based on just the lines identified as changed in the patch set. This is a helpful feature for incrementally improving your codebase. You can, for example,

The patch file must be in Unified diff format, taken from the root directory of your project. (The same directory that holds your Guardrail config file.)

set:

 
{
    "emit" : "Standard.VariableVariable",
    "when" : "new"
}

to emit a "Standard.VariableVariable" error only when the error occurs in the patchset that you are testing. At BambooHR, we have wired this in to our RapidCI setup so that every new commit is tested to a higher standard than we can enforce on the legacy code. Using this approach you can raise the quality of your codebase over time.

Object casting

Languages like Java or C# support casting an object reference from one type to another. This allows you to convert an object that supports multiple interfaces from one interface to another. That nature of the object hasn't changed, just the way the compiler understands it.

In PHP this type of conversion is unnecessary. If an object has a method with the correct name then it can be invoked.

For purposes of static analysis it is important that you only invoke documented methods of an interface. If you are passing an object that implements multiple interfaces, you need to "cast" that object to access one of the interfaces.
Guardrail will honor the result of a simple if() statement containing only a variable and an "instanceof" operation. This is usually a benign change to make because you would never want to call an interface method if the object didn't implement that interface.

 if($var instanceof Foo) { 
    $var->fooInterfaceMethod(); // $var assumed to be a "Foo" inside this clause.
 }
 

If you have an instance of a variable that is ALWAYS a subtype, then you can use either of these cast techniques as well:

 assert($var instanceof Foo); // PHP 7 asserts. 
 

or

 /** var Foo $var  Typical doc block cast. */
 

Links

Plugin architecture


All versions of guardrail with dependencies

PHP Build Version
Package Version
Requires nikic/php-parser Version ^4.2
webmozart/glob Version ^4.1.0
n98/junit-xml Version ^1.0.0
seld/jsonlint Version ^1.7
ext-pcntl Version *
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package bamboohr/guardrail contains the following files

Loading the files please wait ....