#!/bin/sh
# quickcheck.sh: zero-install PHP2Shell triage.
#
# Finds the PHP versions on this host's PATH and tells you whether each is
# affected by PHP2Shell (CVE-2026-109618 / CVE-2026-109619), using only POSIX
# shell and the fixed-version thresholds baked in below. No network, no deps.
#
# It only reads `php -v`; it does not inspect your configuration, dependencies,
# code, or whether running workers still hold the old binary. For that:
#
#     python3 phpshield.pyz scan
#
# Fixed releases (php.net, 2026-10-21): 8.5.12, 8.4.27, 8.3.36, 8.2.35.
# PHP 8.1 and older are end-of-life and receive no official PHP2Shell fix.

set -eu

FIXED_85=12
FIXED_84=27
FIXED_83=36
FIXED_82=35

RED=''; GRN=''; YEL=''; BLD=''; RST=''
if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then
  RED=$(printf '\033[31m'); GRN=$(printf '\033[32m'); YEL=$(printf '\033[33m'); BLD=$(printf '\033[1m'); RST=$(printf '\033[0m')
fi

found=0
affected=0
eol=0

verdict() {
  major=$1; minor=$2; patch=$3; bin=$4
  branch="${major}.${minor}"
  fixed=""
  if [ "$major" = "8" ] && [ "$minor" = "5" ]; then fixed=$FIXED_85
  elif [ "$major" = "8" ] && [ "$minor" = "4" ]; then fixed=$FIXED_84
  elif [ "$major" = "8" ] && [ "$minor" = "3" ]; then fixed=$FIXED_83
  elif [ "$major" = "8" ] && [ "$minor" = "2" ]; then fixed=$FIXED_82
  fi
  if [ -z "$fixed" ]; then
    eol=$((eol + 1))
    printf '%s  %-28s PHP %s.%s.%s   %sEND OF LIFE%s  no official fix for branch %s; migrate to 8.5.%s or 8.4.%s\n' "$RED" "$bin" "$major" "$minor" "$patch" "$BLD" "$RST" "$branch" "$FIXED_85" "$FIXED_84"
  elif [ "$patch" -lt "$fixed" ]; then
    affected=$((affected + 1))
    printf '%s  %-28s PHP %s.%s.%s   %sAFFECTED%s     upgrade to %s.%s\n' "$RED" "$bin" "$major" "$minor" "$patch" "$BLD" "$RST" "$branch" "$fixed"
  else
    printf '%s  %-28s PHP %s.%s.%s   %sPATCHED%s      (fix is %s.%s or newer)\n' "$GRN" "$bin" "$major" "$minor" "$patch" "$BLD" "$RST" "$branch" "$fixed"
  fi
}

printf '%sPHPShield quickcheck: PHP2Shell (CVE-2026-109618 / CVE-2026-109619)%s\n' "$BLD" "$RST"
printf 'Scanning PHP binaries on PATH...\n\n'

IFS=:
for dir in $PATH; do
  [ -d "$dir" ] || continue
  for bin in "$dir"/php "$dir"/php[0-9]* "$dir"/php-fpm* "$dir"/php-cgi*; do
    [ -x "$bin" ] || continue
    out=$("$bin" -v 2>/dev/null | head -n 1) || continue
    ver=$(printf '%s' "$out" | sed -n 's/^PHP \([0-9][0-9]*\)\.\([0-9][0-9]*\)\.\([0-9][0-9]*\).*/\1 \2 \3/p')
    [ -n "$ver" ] || continue
    found=$((found + 1))
    # shellcheck disable=SC2086
    verdict $ver "$bin"
  done
done
unset IFS

if [ "$found" -eq 0 ]; then
  printf '%sNo PHP binary found on PATH.%s A web server may still bundle its own PHP\n(FPM, mod_php, LiteSpeed lsphp). Check the version your site reports and run the\nfull tool to inspect it: python3 phpshield.pyz scan\n' "$YEL" "$RST"
  exit 0
fi

printf '\n'
if [ "$affected" -gt 0 ] || [ "$eol" -gt 0 ]; then
  printf '%s%d affected, %d end-of-life.%s Patch now: https://phpshield.live/fixes/\n' "$RED" "$affected" "$eol" "$RST"
  exit 1
fi
printf '%sEvery PHP binary on PATH carries the PHP2Shell fix.%s Running workers may still hold the old binary; restart them and run the full scan.\n' "$GRN" "$RST"
exit 0
