spatie/ssl-certificate
Retrieve and validate SSL/TLS certificates for any host in PHP. This package fetches certificate details like issuer, validity dates, and expiration status, making it easy to monitor domains and detect upcoming certificate issues in Laravel apps.
Install the package via Composer:
composer require spatie/ssl-certificate
Start by fetching and inspecting a certificate for a domain:
use Spatie\SslCertificate\SslCertificate;
$certificate = SslCertificate::createForHost('example.com');
echo $certificate->issuer(); // "DigiCert Inc"
echo $certificate->subject(); // "example.com"
echo $certificate->expiresAt()->diffForHumans(); // "in 45 days"
echo $certificate->isValid() ? '✅ Valid' : '❌ Invalid';
For early warnings, check if a certificate is about to expire:
if ($certificate->expiresIn(30)) {
// Trigger alert: cert expires in ≤30 days
}
💡 First use case: Run this in a Tinker session or quick artisan tinker command to prototype.
Scheduled Monitoring
Wrap checks in a scheduled command to log/expose expiry alerts:
// app/Commands/CheckCertificateExpiry.php
public function handle()
{
$domains = ['app.yourapp.com', 'api.yourapp.com'];
foreach ($domains as $domain) {
$cert = SslCertificate::createForHost($domain);
if ($cert->expiresIn(14)) {
dispatch(new ExpireNotificationJob($domain, $cert->expiresAt()));
}
}
}
Register it in App\Console\Kernel::schedule().
Health Checks in Laravel
Use in a custom health check (e.g., with spatie/laravel-health):
use Spatie\Health\Checks\Check;
use Spatie\Health\Checks\Result;
class SslCertificateCheck extends Check
{
public function run(): Result
{
$cert = SslCertificate::createForHost('app.example.com');
if ($cert->expiresIn(7)) {
return Result::make()->failed('Certificate expires soon');
}
return Result::make()->ok();
}
}
Batch Processing with Custom Ports
Support non-standard ports (e.g., SMTPS on 465):
$cert = SslCertificate::createForHost('smtp.example.com', 465);
$daysLeft = $cert->daysUntilExpiry();
Error Handling
Use try/catch or fallback defaults—no exception thrown for unreachable hosts; instead, isValid() returns false and error() provides details:
try {
$cert = SslCertificate::createForHost($host, 443);
if (! $cert->isValid()) {
logger()->warning("SSL issue for $host: {$cert->error()}");
}
} catch (\Exception $e) {
// Handle network-level errors (e.g., DNS failure)
}
isValid() checks only the chain validity and expiration, not revocation status. For production-critical apps, consider integrating CRL/OCSP separately.
The package uses phpseclib internally. If certificates fail to parse (e.g., self-signed or non-standard encodings), check error() first before debugging code.
Certificate chain verification: By default, the package verifies the chain against system CA bundle. Override via config if needed (e.g., SslCertificate::createForHost($host, 443, $caBundlePath)), but most Laravel apps work out of the box.
Timezone matters: expiresAt() returns a Carbon instance in the server’s default timezone. Always convert to UTC if storing or comparing across regions:
$expiresAt = $certificate->expiresAt()->setTimezone('UTC');
You can fetch all certificate details as an array via getCertificateDetails() — useful for audit logs or debugging:
$details = $certificate->getCertificateDetails();
// Includes: 'version', 'serial', 'issuer', 'subject', 'validFrom', 'validTo', etc.
🐞 Common pitfall: createForHost() does not follow redirects (e.g., http://example.com → https://www.example.com). Use the HTTPS domain explicitly.
For non-Laravel PHP projects, ensure openssl extension is enabled. No extra config needed in Laravel — works out-of-the-box.
How can I help you explore Laravel packages today?