digitalkaoz/versioneye-php
A PHP client for the VersionEye API that lets you query package metadata, monitor dependencies, and check for outdated or vulnerable libraries directly from your PHP applications.
First, confirm your premise. VersionEye (the SaaS at versioneye.com) shut down in 2017. Every endpoint this client targets is gone, so digitalkaoz/versioneye-php is effectively an unmaintained API-client reference, not a working tool. Treat it as (a) an example of how to wrap a dependency-security API, or (b) a client you can repoint at a self-hosted/compatible service by overriding the base URI. If you need live vuln scanning today, skip to the alternatives in Gotchas and Tips.
Install (for study or forking):
composer require digitalkaoz/versioneye-php
Expect dependency friction on modern Laravel — it pins old Guzzle/PHP constraints:
composer require digitalkaoz/versioneye-php --ignore-platform-reqs
Where to look first:
bin/versioneye — the Symfony Console entry point; run php vendor/bin/versioneye list to see available commands.src/ — the API client/service classes (projects, dependencies, security, licenses).composer.json — check the Guzzle and PHP constraints before assuming Laravel 10/11 compatibility.Configure the key (VersionEye used a per-user API key sent as a query param or token):
VERSIONEYE_API_KEY=your-token-here
VERSIONEYE_API_URL=https://www.versioneye.com/api/v2
First use case — the one that mattered day-to-day: scan a Laravel app's composer.lock for known CVEs and license violations, then fail CI on high-severity findings. The client's project/dependency endpoints map roughly to: create/register a project → upload or reference the manifest → poll the security report → render a table.
VERSIONEYE_API_KEY=$KEY php vendor/bin/versioneye project:list
1. Shell out to the CLI from CI (least coupling).
# .github/workflows/security.yml
- run: composer install --no-dev
- run: php vendor/bin/versioneye project:security --project-id=${{ secrets.VE_PROJECT }} --fail-on=high
This is how the package was intended to be consumed — a throwaway binary in a build image, not a long-lived app dependency.
2. Wrap the client in a Laravel service + facade when you want structured output (JSON reports, Slack notifications) instead of console text:
// app/Services/VersionEye.php
namespace App\Services;
use GuzzleHttp\Client;
class VersionEye
{
public function __construct(private Client $http, private string $key) {}
public function securityReport(int $projectId): array
{
return $this->http->get("projects/{$projectId}", [
'query' => ['api_key' => $this->key],
'timeout' => 10,
])->json();
}
}
// app/Providers/AppServiceProvider.php
$this->app->singleton(VersionEye::class, fn () => new VersionEye(
new \GuzzleHttp\Client(['base_uri' => config('services.versioneye.url')]),
config('services.versioneye.key'),
));
3. Scheduled Artisan command — nightly dependency drift + CVE checks across all your apps:
class ScanDependencies extends Command
{
protected $signature = 'deps:scan {project : VersionEye project id}';
public function handle(VersionEye $ve): int
{
$report = $ve->securityReport((int) $this->argument('project'));
$high = collect($report['dependencies'] ?? [])
->filter(fn ($d) => ($d['security']['severity'] ?? 'none') === 'high');
if ($high->isNotEmpty()) {
Log::warning('Vulnerable deps', $high->pluck('name')->all());
return self::FAILURE;
}
return self::SUCCESS;
}
}
4. Cache reports between runs. VersionEye reports change slowly; cache by composer.lock hash to avoid hammering the API (and to survive rate limits):
$report = Cache::remember("ve:{$project}:".md5_file(base_path('composer.lock')), now()->addHours(6), fn () => $ve->securityReport($project));
5. Poll-then-fetch. The API was asynchronous for new project uploads: submit the manifest, then poll a status/report endpoint until status === 'done'. Bake in a bounded retry (e.g., 5 × 10s) rather than assuming an immediate response.
6. Report to humans. Map API fields into a Markdown table (package, installed version, fixed-in version, severity, license) and post to Slack/PR comment — this is where most day-to-day value came from.
>=5.5 constraints conflict with Laravel 8+. Use --ignore-platform-reqs, or better, copy the handful of HTTP calls into your own GuzzleHttp\Client (the client logic is thin).composer require ... :0.33 and isolate behind your own interface so removal is a one-line change.page until an empty result instead of assuming one response. Throttle to ~1 req/sec.config('services.versioneye.url') in config so you can swap it without touching call sites.composer audit (built into Composer 2.4+) or symfony/security-checker — local, no service needed.roave/security-advisories as a dev dependency — blocks vulnerable installs at composer update time.osv-scanner or Snyk CLI in CI — actively maintained, supports composer.lock.composer licenses / composer-unused for license and bloat checks.MockHandler) rather than relying on the dead API — the classes will still parse JSON correctly.How can I help you explore Laravel packages today?