How to check if domain has SSL certificate or not?
This function will not only check if the domain has a SSL certificate, but also confirms, if the certificate matches the requested domain.
The most important part is the function openssl_x509_parse
which parses the certificate and returns all the details as array.
function has_ssl( $domain ) {
$res = false;
$stream = @stream_context_create( array( 'ssl' => array( 'capture_peer_cert' => true ) ) );
$socket = @stream_socket_client( 'ssl://' . $domain . ':443', $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $stream );
// If we got a ssl certificate we check here, if the certificate domain
// matches the website domain.
if ( $socket ) {
$cont = stream_context_get_params( $socket );
$cert_ressource = $cont['options']['ssl']['peer_certificate'];
$cert = openssl_x509_parse( $cert_ressource );
// Expected name has format "/CN=*.yourdomain.com"
$namepart = explode( '=', $cert['name'] );
// We want to correctly confirm the certificate even
// for subdomains like "www.yourdomain.com"
if ( count( $namepart ) == 2 ) {
$cert_domain = trim( $namepart[1], '*. ' );
$check_domain = substr( $domain, -strlen( $cert_domain ) );
$res = ($cert_domain == $check_domain);
}
}
return $res;
}
Finally, I've ended up with the following my code:
$stream = stream_context_create (array("ssl" => array("capture_peer_cert" => true)));
$read = fopen("https://www.example.com", "rb", false, $stream);
$cont = stream_context_get_params($read);
$var = ($cont["options"]["ssl"]["peer_certificate"]);
$result = (!is_null($var)) ? true : false;
If HTTPS is enabled for a domain, var_dump($var)
gives the output as shown:
resource(4) of type (OpenSSL X.509)
If it doesn't exist it returns NULL
.
I've checked a few domains. It seems to be working fine. I hope it will help someone.
There's no way to check if the certificate is secure or not using PHP alone without API (green padlock)
But you can use this, which use a API: https://github.com/spatie/ssl-certificate
Here is a different solution that I found somewhere on github (cannot find the repo again...)
It's a similar approach to the accepted answer, but uses fsockopen to test, if we can establish a SSL connection on port 443. If the connection is refused then the domain does not have a ssl certificate.
function has_ssl( $domain ) {
$ssl_check = @fsockopen( 'ssl://' . $domain, 443, $errno, $errstr, 30 );
$res = !! $ssl_check;
if ( $ssl_check ) { fclose( $ssl_check ); }
return $res;
}
// Test it:
print_r( has_ssl('google.com') );