Search by

phpsafe / guard

phpsafe-cloud

Zero-dependency security layer for PHP: request shield, static code scanner and safe helpers.

v0.1.0 2026-10-22 07:31 UTC

This package is auto-updated.

Last update: 2026-10-22 08:01:14 UTC


README

phpsafe

PHP Safe Guard

A zero-dependency security layer for any PHP application.
Request shield · static code scanner · safe helpers

CI PHP 8.1+ Zero dependencies MIT license

English · 한국어 · 中文 · 日本語

PHP Safe Guard is the open-source engine behind phpsafe.cloud. It gives an existing PHP site three things:

Part What it does
Shield Inspects every request before your code runs. Blocks SQL injection, XSS, path traversal, code injection, executable uploads and known attack tools. Adds safe security headers and rate-limits login forms.
Scanner Reads your source with PHP's own tokenizer (code is never executed) and reports risky lines with a fix for each one. Runs locally and in CI.
Helpers Small, tested functions for CSRF tokens, context-aware escaping and safe file uploads.

Install

With Composer:

composer require phpsafe/guard

Without Composer, download the latest release and copy the folder anywhere on your server. Nothing else is required: no extensions, no services, no database.

Shield

Add one line so Shield runs before every PHP file.

php.ini (or .user.ini on shared hosting):

auto_prepend_file = /path/to/phpsafe-guard/shield.php

Or at the very top of your front controller:

require __DIR__ . '/vendor/phpsafe/guard/shield.php';

That's it. Blocked visitors see a short page in their language (English, Korean, Chinese or Japanese) with an incident ID, and every event is written to guard.log as one JSON line.

Settings

Copy guard.config.example.php to guard.config.php next to shield.php, or point the PHPSAFE_GUARD_CONFIG environment variable to your own file. Every key is optional.

return [
    'mode'         => 'block',                 // or 'log' to only record
    'allow_params' => ['content'],             // fields that legitimately contain HTML
    'allow_paths'  => ['/admin/editor'],       // paths Shield skips
    'login_paths'  => ['/login'],              // brute-force protection
    'storage'      => '/var/lib/phpsafe',      // log + counters, outside the web root
];

Rolling out on an existing site: start with 'mode' => 'log' for a few days, read guard.log, add any rich-text fields to allow_params, then switch to 'block'.

What Shield checks

Family Examples it stops
SQL injection UNION SELECT, ' OR '1'='1, '--, stacked queries, SLEEP(), information_schema
XSS <script>, event handlers like onerror=, javascript: URLs, <svg>, <iframe>
Path traversal ../, /etc/passwd, php://filter, NUL bytes
Code injection <?php in input, system(, shell pipes like ; cat, ${jndi:
Uploads .php, .phtml, .phar, double extensions like cat.php.jpg, .htaccess, PHP code hidden inside images
Tools sqlmap, nikto, wpscan, nuclei and other attack scanners

Values are URL-decoded, entity-decoded and normalised before matching, so encoded payloads are caught too.

Scanner

vendor/bin/phpsafe scan              # scan the current folder
vendor/bin/phpsafe scan src --lang=ko
vendor/bin/phpsafe scan . --format=json > report.json
 CRITICAL  SQL built with variables (SQL injection)
   app/login.php:14  $db->query("SELECT * FROM users WHERE name = '$name'");
   Fix: Use prepared statements: $db->prepare('... WHERE id = ?') then execute([$id]).

────────────────────────────────────────────────
Grade C  62/100   48 files · 5,210 lines
 Critical 1   High 2   Medium 1   Low 0
Option Meaning
--fail-on=high Exit code 1 when a finding of this level or worse exists (critical, high, medium, low, none). Use it to stop risky code in CI.
--format=json Machine-readable output
--exclude=a,b Extra folders or files to skip (vendor, node_modules, .git are always skipped)
--lang=en|ko|zh|ja Message language

Silence a reviewed line with a comment on the same line:

$config = require $file; // phpsafe-ignore: path comes from server config

GitHub Actions

- run: composer require --dev phpsafe/guard
- run: vendor/bin/phpsafe scan src --fail-on=high

Rules

eval · shell execution · file inclusion from input · variable include paths · XSS · SQL built from variables · unserialize · extract on request data · preg_replace /e · file access from input · uploads saved with the original name · open redirect · md5/sha1 · predictable random numbers · phpinfo · display_errors turned on · SSL verification turned off · debug output of request data

Helpers

use PhpSafe\Guard\Csrf;
use PhpSafe\Guard\Escape;
use PhpSafe\Guard\Upload;

// CSRF
echo csrf_field();                                   // inside your <form>
if (!Csrf::verify($_POST['_csrf'] ?? null)) { http_response_code(419); exit; }

// Escaping
echo e($name);                                       // HTML text
echo '<a href="' . Escape::safeUrl($link) . '">';    // blocks javascript: URLs
echo '<script>const user = ' . Escape::js($user) . ';</script>';

// Uploads: real MIME check, random name, size limit, no hidden PHP
$file = Upload::store($_FILES['avatar'], '/var/app-uploads', Upload::IMAGES, 2_000_000);

See examples/ for complete pages.

What Guard is, and what it is not

Guard is an extra layer of defense. Pattern matching catches the large majority of automated and copy-paste attacks, but it cannot understand your application's logic. It does not replace:

  • prepared statements for every query
  • escaping every value you print
  • keeping PHP, your framework and dependencies updated (composer audit)

Use it together with those basics, and with a full WAF such as ModSecurity + OWASP CRS on high-traffic sites.

Development

php tests/run.php                        # test suite, no dependencies needed
php bin/phpsafe scan . --fail-on=low     # Guard scans itself and must stay clean

Found a bypass or a false positive? Please read SECURITY.md for bypasses and open an issue for false positives.

License

MIT © PHP Safe — phpsafe.cloud