PHP Censor: a self-hosted CI server for PHP projects
PHP Censor is an open source self-hosted continuous integration server for PHP projects.
At a glance
- What is it?
- PHP Censor is a PHP 7.4+ continuous integration server you host yourself, configured with a .php-censor.yml file in your repository. It fits teams that want their build pipeline on their own hardware and are willing to run Beanstalkd, a database and a web server to get it.
- Who is it for?
- Adopt PHP Censor if you run PHP 7.4 or newer on a Unix host you control, already have MySQL, MariaDB or PostgreSQL and Beanstalkd available, and want build configuration to live in a .php-censor.yml file in the repository rather than in a vendor's cloud. Do not adopt it on Windows, which the system requirements state is not supported, and do not expect it to cover languages other than PHP.
- Can I use it commercially?
- Yes. BSD-2-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 123 days ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What PHP Censor solves, and who it is aimed at
PHP Censor is a fork of PHPCI, and it does one job: run a build for a PHP repository on a server you own. The README describes it as an open source, self-hosted, continuous integration server for PHP projects. The self-hosted part is the whole point. If your code cannot leave your network, or you do not want a hosted CI provider holding repository credentials, this is the category of tool you look at.
The audience is narrow and specific. You need a Unix-like operating system, because the system requirements state plainly that Windows is not supported. You need PHP 7.4 or newer with OpenSSL support and the exec(), shell_exec() and proc_open() functions enabled, which rules out hardened shared hosting where those functions are disabled. You need a web server (Nginx or Apache2), a database (MySQL, MariaDB or PostgreSQL), and Beanstalkd as a queue. That is four moving parts before the first build runs.
In exchange, the build definition lives in your repository. The README notes that, similar to Travis CI, you add a .php-censor.yml file to the root of your repository. A project can also be added with no config at all, in which case PHP Censor runs a set of zero-config plugins covering Composer, TechnicalDebt, PHPLoc, PHPCpd, PHPCodeSniffer, PHPMessDetector, PHPDocblockChecker, PHPParallelLint, PHPUnit and Codeception. That default set is the useful part for a legacy PHP codebase: you get linting, static checks and test execution without writing any YAML.
The build pipeline: config file, queue worker, plugins
The mechanism is a three-stage build. The .php-censor.yml file defines stages named setup, test and complete, and each stage holds plugin entries. The README's example config shows Composer under setup, PHPUnit and code-quality tools under test, and email notification under complete. Each plugin entry is a mapping whose keys depend on the plugin: the example sets action and directory for Composer, config for PHPUnit, standard for PHPCodeSniffer, and allow_failures for the tools whose findings should not break the build.
The separation between test and complete matters in practice. Anything that should run regardless of whether tests passed belongs in complete, which is where the example puts the notification plugin. A build that fails at the test stage still reaches complete and still sends the mail.
Execution is not synchronous with the web request. Beanstalkd is listed as a system requirement, and the Makefile exposes a run-worker target that runs bin/console php-censor:worker -v. The web interface accepts a build, the job goes onto the queue, and the worker process picks it up and runs the plugins. That means the web server and the worker are separate processes, and a stopped worker produces builds that sit in the queue with no output. It also means the worker needs the same PHP environment as the web front end, since it is the process that shells out to Composer and the test runners.
Sources are handled by plugins rather than by a single hardcoded Git client. The feature list names GitHub, Bitbucket (Git and Hg), GitLab, plain Git, Mercurial, SVN and local directory as clone sources. If your repository lives somewhere that is not on that list, there is no generic fallback described in the README.
Installing PHP Censor and running a first build
The README does not inline the install steps. It points to a separate Installing page under docs/en/installing.md, so the exact sequence of commands lives there rather than in the top-level file. What the repository does show is the dependency install path via Composer, and the Makefile targets that the project itself uses.
The Makefile defaults to PHP 7.4 and expects Composer at /usr/local/bin/composer. The install target only runs Composer when a vendor directory is absent, so re-running it on an existing checkout is a no-op.
make install
make install PHP=php8.0The first command installs dependencies with the default PHP binary. The second shows the override the Makefile documents in its own comments, which is how you point the install at a different PHP version on the same host.
Once the application is in place, the database schema has to be applied. The README gives the migration command directly, and it must be run from the PHP Censor directory.
cd /path/to/php-censor
./bin/console php-censor-migrations:migrateAfter migrations, the queue worker has to be running for builds to execute. The Makefile target wraps the console command.
make run-workerThat runs bin/console php-censor:worker -v. The -v flag is the verbosity level the Makefile passes. With the worker up, you add a project in the web interface, point it at a repository, and either let the zero-config plugins run or commit a .php-censor.yml file. The README's example config is the shortest complete one to start from:
setup:
composer:
action: "install"
directory: "."
test:
php_unit:
config: "phpunit.xml"
php_mess_detector:
allow_failures: true
php_code_sniffer:
standard: "PSR2"
php_cpd:
allow_failures: true
complete:
email_notify:
default_mailto_address: [email protected]What you should see after a push is a build entry in the dashboard with per-plugin output. The two allow_failures entries mean PHPMessDetector and PHPCpd report their findings without failing the build, which is the right default when you are introducing static analysis to a codebase that has never been checked.
Where PHP Censor gets in the way
The Windows exclusion is not a footnote. The system requirements state it outright, and since the worker shells out to Composer and test runners, there is no partial workaround described in the README. If your build machines are Windows, this project is not for you.
The function requirements are a second hard boundary. exec(), shell_exec() and proc_open() must be enabled. Any hosting setup that disables process execution for security reasons cannot run PHP Censor at all, because running external tools is the entire function of the worker.
Version support is uneven. The version table marks 1.0 through 1.3 as unsupported and requires PHP 5.6 to below 8.0 for them. Version 2.0 is labelled the last stable version, 2.1 is the current stable version, and 2.2 is marked WIP on master. Both 2.0 and 2.1 require PHP 7.4 or newer. The practical consequence is that upgrading from a 1.x install is a documented migration rather than a patch bump, and the README links a dedicated upgrade guide for the 1 to 2 move.
The default branch tracks 2.2, which the README itself describes as a feature minor version in progress. Running master means running WIP code. The stable line to pin is release-2.1. The last push to the repository was on 2026-05-31, and the most recent release listed is 2.1.6 from 2025-03-15, so the release cadence is slow rather than continuous.
Finally, the plugin list is PHP-shaped. Composer, PHPUnit, Atoum, Behat, Codeception, PHPSpec, PHPCodeSniffer, PHPMessDetector and the rest are all PHP tooling. There are generic Shell and Grunt and Gulp plugins, but nothing here suggests PHP Censor is a general-purpose multi-language CI server. If your repository is mostly JavaScript or Go, the PHP-oriented defaults are dead weight.
PHP Censor against a hosted CI service
The obvious alternative is a hosted service such as Travis CI, which the README itself names when explaining the .php-censor.yml approach. The difference is where the work runs and who holds the credentials. A hosted service clones your repository onto its infrastructure and runs the build there. PHP Censor clones your repository onto your own machine, using the source plugins for GitHub, GitLab, Bitbucket, plain Git, Mercurial, SVN or a local directory.
That changes the operational surface. With a hosted service you maintain a config file and nothing else. With PHP Censor you maintain the config file plus a web server, a database, Beanstalkd and a worker process. The README's Makefile has targets for running tests, mutation tests, Psalm, Rector and code style checks, which tells you the project expects you to be comfortable operating a PHP application, not just writing YAML.
What you get back is control over the environment. Database test setup plugins for PostgreSQL, MySQL and SQLite are listed as a feature, which means a build can create and tear down a real database on your own infrastructure rather than a service-provided one. LDAP authentication is supported, so the web interface can sit behind your existing directory. Notifications go to Email, XMPP, Slack, IRC, Flowdock and Telegram.
A second comparison worth making is with simply running the same tools from a shell script in your existing pipeline. PHP Censor's value over that is the dashboard, the build history, the per-plugin result breakdown and the queued worker model. If you only need Composer install plus PHPUnit on every push, a shell script is less infrastructure to keep alive.
Maintenance, upgrades and the BSD-2-Clause licence
The upgrade path is versioned and explicit. The README's table lists each line with its own branch: release-1.0, release-1.1, release-1.2, release-1.3, release-2.0 and release-2.1. Upgrading across major versions is not a matter of pulling the latest tag. The 1 to 2 move has its own guide at docs/UPGRADE_2.0.md, and the PHP floor changes from the 5.6 to 8.0 window in 1.x to 7.4 or newer in 2.x. If you are on a 1.x release, treat the upgrade as a project, not a maintenance task.
Database migrations are a recurring cost. Any upgrade that changes the schema requires running ./bin/console php-censor-migrations:migrate from the application directory. The same console offers php-censor-migrations:create for writing a new migration, which matters only if you are extending the application itself.
The worker is the piece most likely to need attention in production. It is a long-running process, and the Makefile runs it with -v. Nothing in the README describes a supervisor configuration or a restart policy, so process supervision is left to whatever your host already provides.
The licence is BSD-2-Clause, which the README lists and which Packagist reports for the package. That is a permissive licence: it allows use and redistribution with the copyright notice and the disclaimer retained, and it does not carry the copyleft obligations of the GPL family. It also does not include an explicit patent grant, which some organisations prefer to see. Whether that matters to your legal team is a question for them, not something this article can settle. The one concrete implication worth noting is that self-hosting a BSD-2-Clause application inside a company raises no source-disclosure question for your own code.
Editorial conclusion
Adopt PHP Censor if you run PHP 7.4 or newer on a Unix host you control, already have MySQL, MariaDB or PostgreSQL and Beanstalkd available, and want build configuration to live in a .php-censor.yml file in the repository rather than in a vendor's cloud. Do not adopt it on Windows, which the system requirements state is not supported, and do not expect it to cover languages other than PHP. Before committing, verify that your host has exec(), shell_exec() and proc_open() enabled, that a queue daemon is running, and that your intended source (Git, Mercurial, SVN or a local directory) is supported by the plugin you plan to use.
Frequently asked questions
Does PHP Censor require Beanstalkd?
Yes. The system requirements list Beanstalkd as a queue alongside the web server and database, and the Makefile exposes a run-worker target that starts bin/console php-censor:worker -v.
Can PHP Censor run on Windows?
No. The system requirements state that a Unix-like OS is needed and that Windows is not supported.
Which PHP version does PHP Censor need?
Version 2.0 and 2.1 both require PHP 7.4 or newer, and the README badge gives 7.4.0 as the minimum. The older 1.x lines required PHP 5.6 up to below 8.0 and are marked unsupported.
How do I configure a project in PHP Censor?
Add a .php-censor.yml file to the root of your repository, with setup, test and complete stages holding plugin entries. A project can also be added with no config, in which case PHP Censor runs a set of zero-config plugins including Composer, PHPUnit, Codeception and several code-quality tools.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/php-censor-php-censor)