PHP-Facedetect is a small native PHP extension that exposes OpenCV's cascade classifier through two functions. It was created when invoking computer-vision code directly from PHP usually meant writing an extension or maintaining a separate service. The wrapper keeps that boundary deliberately narrow: give it an image and a trained cascade, then receive either the number of detections or their bounding rectangles.
The project performs face detection, not face recognition. It locates regions that resemble the objects represented by a cascade; it does not identify a person, compare identities, estimate attributes, or determine whether a detected face belongs to a real person.
Project Status
The source remains available under the BSD 3-Clause license in the PHP-Facedetect repository. The current source reports version 0.1.0, detects OpenCV 3 and OpenCV 4 through pkg-config, contains compatibility work for PHP 7, PHP 8, and PHP 8.1, and last received a repository update in 2022.
The old instruction pecl install facedetect is no longer valid: there is no current Facedetect package in the PECL registry, and PECL itself is deprecated in favor of PIE. This repository does not currently contain PIE package metadata or an automated compatibility matrix. Treat it as a historical native extension that may require maintenance for a current PHP, compiler, and OpenCV combination. Build and test it in the same container or operating system image used in production.
As a point-in-time verification for this migration, the current master branch compiled, linked, and loaded successfully with PHP 8.4.1 and OpenCV 4.12.0 on arm64 macOS. Reflection reported the documented PHP 8 return types. An end-to-end smoke test also decoded a JPEG with OpenCV's official frontal-face cascade and returned a bounding box. This result validates that exact environment; it is not a compatibility promise for other versions or platforms.
API
Both functions take a readable image pathname and an optional cascade pathname:
face_detect(string $imagePath, ?string $cascadePath = null): array|false
face_count(string $imagePath, ?string $cascadePath = null): int|false face_detect() returns one associative array per detected region. Coordinates are pixel values measured from the image's top-left corner:
<?php
$cascade = '/opt/opencv-data/haarcascades/haarcascade_frontalface_default.xml';
$image = '/srv/facedetect/input/group.jpg';
$faces = face_detect($image, $cascade);
if ($faces === false) {
throw new RuntimeException('The image or cascade could not be processed.');
}
foreach ($faces as $face) {
printf(
"x=%d y=%d width=%d height=%d\n",
$face['x'],
$face['y'],
$face['w'],
$face['h'],
);
} A successful call with no detections returns an empty array. A successful face_count() call returns zero in that case:
<?php
$count = face_count($image, $cascade);
if ($count === false) {
throw new RuntimeException('The image or cascade could not be processed.');
}
printf("Detected faces: %d\n", $count); The count function runs the same detection pipeline; it is not cheaper in computer-vision work. It only avoids constructing and returning the rectangle arrays.
How Detection Works
The implementation reads the image with OpenCV, converts it from BGR to grayscale, equalizes the grayscale histogram, and calls CascadeClassifier::detectMultiScale(). Its fixed parameters are a scale factor of 1.1, minNeighbors = 2, and a minimum detection size of 30 by 30 pixels.
The cascade XML file is therefore part of the model, not a generic configuration detail. A frontal-face cascade, a profile-face cascade, and a body cascade solve different detection tasks and produce different errors. OpenCV ships pretrained Haar cascades in its source data directory, while operating-system packages install them in distribution-specific locations.
A historical comparison of frontal, profile, and body cascades on the same image illustrates how model choice changes the selected region and can create false positives.
A cascade can also be loaded once through the extension setting:
; php.ini or a dedicated conf.d/facedetect.ini file
extension=facedetect.so
facedetect.cascade=/opt/opencv-data/haarcascades/haarcascade_frontalface_default.xml After that, calls may omit the second argument:
<?php
$faces = face_detect('/srv/facedetect/input/group.jpg'); If neither the call nor facedetect.cascade supplies a successfully loaded classifier, the function emits a warning and returns false. Passing a cascade path loads that classifier into the extension's shared classifier object and affects later calls in the same PHP process. Prefer one fixed startup configuration in a long-running PHP-FPM worker rather than switching models per request.
Build from Source
A source build requires a C++ compiler, PHP development headers that match the target PHP runtime, phpize, php-config, pkg-config, and OpenCV development files. The build script accepts either an opencv.pc or opencv4.pc package with version 3.0.0 or newer.
git clone https://github.com/infusion/PHP-Facedetect.git
cd PHP-Facedetect
phpize
./configure --with-facedetect --with-php-config="$(command -v php-config)"
make -j"$(getconf _NPROCESSORS_ONLN 2>/dev/null || printf 1)"
make test
sudo make install The repository currently has no bundled test suite, so make test may report that no tests exist. It is still worth running because downstream packaging may add tests. Do not run sudo for cloning, configuring, or compiling; installation is the only step that may need elevated privileges.
Enable the module for the correct Server API:
printf '%s\n' 'extension=facedetect.so' | \
sudo tee "$(php --ini | sed -n 's|Scan for additional .ini files in: ||p')/facedetect.ini"
php --ri facedetect The command above assumes that the CLI scans a writable configuration directory and that it matches the target runtime. PHP CLI and PHP-FPM often load different configuration trees. Verify both with php --ini and the FPM package's own configuration before restarting the service. A package-managed conf.d file is preferable to editing the main php.ini.
Verify the Build
Before processing real images, verify module loading, both public functions, and OpenCV linkage:
php --ri facedetect
php -r 'var_dump(extension_loaded("facedetect"));'
php -r 'var_dump(function_exists("face_detect"), function_exists("face_count"));'
php -r '
$faces = face_detect($argv[1], $argv[2]);
if ($faces === false) {
exit(1);
}
echo json_encode($faces, JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT), PHP_EOL;
' /srv/facedetect/test.jpg /opt/opencv-data/haarcascades/haarcascade_frontalface_default.xml Keep the image and expected cascade in a deployment smoke test. Loading the module proves ABI compatibility only far enough for startup; decoding an image and executing the classifier exercises the OpenCV path that the application actually needs.
Operational and Security Limits
- Do not pass arbitrary client paths. Resolve uploads to server-generated filenames inside a private directory. The extension reads filesystem paths directly.
- Validate uploads before detection. Enforce byte and pixel limits, decode outside the request path when possible, and isolate native processing from the public web worker.
- Treat failures as expected. Missing files, unreadable images, and invalid cascades emit warnings and return
false; distinguish that value from an empty successful result. - Expect false positives and false negatives. Haar cascades are fast and historically important, but lighting, pose, occlusion, scale, and training data strongly affect results.
- Do not infer identity or sensitive traits. Bounding boxes contain no identity claim. Face processing can also trigger privacy, consent, retention, and biometric-data obligations.
- Pin the complete native stack. PHP, Zend ABI, compiler runtime, OpenCV, the extension commit, and cascade files all belong in the deployment bill of materials.
For new systems, a separate computer-vision service or a maintained binding is usually easier to upgrade and isolate than a custom module loaded into every PHP worker. The extension remains useful where its tiny API, low call overhead, and historical compatibility are specifically valuable.
References
- [Source]PHP-Facedetect source repository.
- [OpenCV]OpenCV: Cascade Classifier tutorial.
- [ViolaJones2004]Paul Viola and Michael J. Jones, “Robust Real-Time Face Detection,” International Journal of Computer Vision, 57(2), 2004, pp. 137–154.
- [phpize]PHP Manual: Compiling shared extensions with phpize.