spatie/mixed-content-scanner
Scan a website for mixed content by crawling pages and flagging insecure http:// resources in common HTML tags (img, script, iframe, link, etc.). Use MixedContentScanner with a logger to report where mixed content is found or missing.
Installation:
composer require spatie/mixed-content-scanner
Add to composer.json if using a monorepo or custom package.
First Use Case: Scan a URL for mixed content (HTTP resources on HTTPS pages) via CLI or programmatically:
use Spatie\MixedContentScanner\MixedContentScanner;
use Spatie\MixedContentScanner\MixedContentLogger;
$logger = new class implements MixedContentLogger {
public function logMixedContentFound(string $url, string $mixedContentUrl) {
echo "Mixed content found at {$url}: {$mixedContentUrl}\n";
}
public function logNoMixedContentFound(string $url) {
echo "No mixed content found at {$url}\n";
}
};
$scanner = new MixedContentScanner($logger);
$scanner->scan('https://your-laravel-app.test');
Key Files:
MixedContentScanner.php: Core logic.MixedContentLogger.php: Interface for logging results.src/: Source directory for all classes.For quick scans, use the companion CLI package:
composer require spatie/mixed-content-scanner-cli
./vendor/bin/mixed-content-scanner scan https://your-laravel-app.test
Pre-Deployment Scans:
Integrate into Laravel’s app/Console/Kernel.php to run scans before deployments:
protected function schedule(Schedule $schedule) {
$schedule->command(MixedContentScannerCommand::class)
->everyFiveMinutes()
->when(function () {
return app()->environment('production');
});
}
Custom Logging:
Extend MixedContentLogger to integrate with Laravel’s logging:
use Illuminate\Support\Facades\Log;
$logger = new class implements MixedContentLogger {
public function logMixedContentFound(string $url, string $mixedContentUrl) {
Log::warning("Mixed content at {$url}: {$mixedContentUrl}");
}
public function logNoMixedContentFound(string $url) {
Log::info("No mixed content at {$url}");
}
};
Batch Scanning: Scan multiple URLs (e.g., from a database):
$urls = Url::where('is_production', true)->pluck('url');
foreach ($urls as $url) {
$scanner->scan($url);
}
Artisan Command: Create a custom command for manual triggering:
php artisan make:command ScanMixedContent
// app/Console/Commands/ScanMixedContent.php
public function handle() {
$scanner = new MixedContentScanner(new MixedContentLogger());
$scanner->scan($this->argument('url'));
}
Usage:
php artisan scan:mixed-content https://your-site.com
use Illuminate\Bus\Queueable;
use Spatie\MixedContentScanner\Jobs\ScanMixedContent;
ScanMixedContent::dispatch('https://your-site.com')->onQueue('scans');
$logger = new class implements MixedContentLogger {
public function logMixedContentFound(string $url, string $mixedContentUrl) {
Notification::route('mail', 'admin@example.com')
->notify(new MixedContentAlert($url, $mixedContentUrl));
}
};
Rate Limiting:
--delay in CLI or add delays in code:
$scanner->setDelayBetweenRequests(2); // 2-second delay
False Positives:
$scanner->ignoreUrls([
'https://cdn.example.com/*',
'https://fonts.googleapis.com/*'
]);
Self-Signed Certificates:
file_get_contents under the hood, which may fail on self-signed certs. Disable SSL verification only for testing:
$scanner->setDisableSslVerification(true); // Avoid in production!
JavaScript/Iframe Content:
Redirects:
$scanner->setFollowRedirects(true); // Default is true
$scanner->setDebug(true);
curl -v or browser dev tools to verify mixed content manually if the scanner misses issues.Custom Scanners:
Extend MixedContentScanner to add logic (e.g., scan only specific paths):
class CustomScanner extends MixedContentScanner {
public function scanOnly(string $url, string $path) {
$fullUrl = rtrim($url, '/') . '/' . ltrim($path, '/');
return $this->scan($fullUrl);
}
}
Database Storage: Store scan results in a table for historical analysis:
// After scanning, save to DB
MixedContentResult::create([
'url' => $url,
'has_mixed_content' => $scanner->hasMixedContent(),
'scanned_at' => now(),
]);
Parallel Scanning:
Use Laravel’s parallel helper or pest/phpunit parallel tests to scan multiple URLs concurrently:
parallel([
fn() => $scanner->scan('https://site1.com'),
fn() => $scanner->scan('https://site2.com'),
]);
CI/CD Integration: Fail builds on mixed content detection (e.g., GitHub Actions):
# .github/workflows/scan.yml
- name: Scan for mixed content
run: |
./vendor/bin/mixed-content-scanner scan https://your-site.com
if [ $? -ne 0 ]; then exit 1; fi
MixedContentScanner as the user agent. Override for better mimicry:
$scanner->setUserAgent('Mozilla/5.0 (compatible; Laravel Scanner/1.0)');
$scanner->setTimeout(30); // 30 seconds
How can I help you explore Laravel packages today?