Search code examples
phpcurlmonitoringpingfsockopen

How to use "fallback" method for PHP curl (HTTPS)?


Situation: I'm improving some code on a PHP based monitoring web app that checks the health of other web apps/services.

Goal: we are using CURL as a primary method to get headers to ensure the monitored app is accessible via HTTP return codes. This works great as of now. However, we are trying to build in a "fallback" method in which IF the CURL HTTP code response from the monitored app is outside of our defined variables (ie http code 404), PHP would then use a PING-like function to check if there is any response at that same address (for example, webserver is still "running" (occupying the given port) but not serving proper headers).

Problem: Our fallback method (stream_socket_client) DOES work for non-secure sites as we can simply define "hostname:port" which BOTH curl and stream_socket_client can use. However, If we want to monitor a secure site (HTTPS), curl requires the HTTPS protocol to be defined before the host - which will then make our fallback method (stream_socket_client) function fail as it only uses host:port format.

So, for example:

$URL: https://example.com:443 (this would turn a "GOOD" CURL response, but a down stream_socket_client response)

$URL: example.com:443 (this would return a "UP" stream_socket_client response, but a "DOWN" CURL response)

So, if we used https://example.com:443 as our URL, and the webserver became unresponsive, but is still running on that port, both would fail because HTTPs is defined.

This is a simplified version of our current code:

<?php

    $url = "example.com:80";

    function curl($url) {



        $handle = curl_init($url);
        curl_setopt($handle,  CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($handle, CURLOPT_HEADER, true);
        curl_setopt($handle, CURLOPT_NOBODY, true);
        curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($handle, CURLOPT_URL, $url);

        $response = curl_exec($handle);
        $httpCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);


        if($httpCode >= 200 && $httpCode < 400 || $httpCode == 401 || $httpCode == 405) {

                echo "CURL GOOD, $httpCode";
                echo "STATUS: GREEN";
            } 

            else {

                $fp = stream_socket_client("$url", $errno, $errstr);

                if (!$fp) {
                    echo "CURL BAD, PING DOWN";
                    echo "STATUS: RED";
                } 

                else {
                    echo "CURL BAD PING UP";
                    echo "STATUS: YELLOW";
                }
            }

        curl_close($handle);

    };
?>

Any ideas how to use a fallback method to check if a port is open or not? I don't have to stick with PHP, can use some JS, but would prefer PHP.

EDIT 1:

Thanks to @drew010 I know I need to ultimately use fsockopen. However, I'll need to use parse_url() which can then pass a "sterile" URL to fsockopen for fallback "ping" check.

However, I'm not sure how to strip ONLY the protocol and leave the port and sub path (if defined). I'm also not sure how to pass the sterile URL to the fsockeopn function to use for the check. So far I have the code below, but I know I'm missing some code.

The below code parses http://example.com to example.com.

function parseurl($url) {
    $url = 'http://example.com:80';
    $host = parse_url($url, PHP_URL_HOST);

    //this works for stripping protocol and "wwww" but need to leave port and sub path if defined.

    if (!$host)
        $host = $url;

    if (substr($host, 0, 4) == "www.")
        $host = substr($host, 4);
    if (strlen($host) > 50)
        $host = substr($host, 0, 47) . '...';
    return $host;
}


  // How to pass steril URL to PING function??

function ping($host, $timeout = 1) {

    if (!fsockopen($host, $port, $errno, $errstr, $timeout)) {
        return false;
        echo "OPEN";
    }

    else {
        echo "CLOSED";
    }
 }

Solution

  • Found the answer:

    This script uses CURL to check if given HOST is serving a webpage. If NOT, use a PING function to check if anything is listening on given port.

    <?php
    
         * This script uses CURL to check if given HOST is serving a webpage. 
         * If NOT, use a PING function to check if anything is listening on given port.
        //* URL MUST contain a PORT after HOST
        //* URL CAN include any protocol or sub-path
    
    
        // sanitizes URL to host:port:path ONLY. (if PORT, PATH don't exist, it is ignored):
    
        function url_to_domain($url) {
    
            $url = 'http://google.com:80';
    
            echo "Input URL ..... $url<br />\n";
    
            $host = parse_url($url, PHP_URL_HOST);
            $port = parse_url($url, PHP_URL_PORT);
            $path = parse_url($url, PHP_URL_PATH);
    
            // If the URL can't be parsed, use the original URL
            // Change to "return false" if you don't want that
    
            if (!$host)
                echo "fail";
                // $host = $url;
    
                // remove "http/s" and "www" :
    
            if (substr($host, 0, 4) == "www.")
                $host = substr($host, 4);
            if (strlen($host) > 50)
                $host = substr($host, 0, 47) . '...';
    
            // contruct sanitized URL, add ":port/path" to HOST:
    
            return $host . ":" . $port . $path;
    
     }
    
    
         // pings "sanitized" URL:
    
        $url = (url_to_domain($url));
    
        $fp = pfsockopen($url, $errno, $errstr, $timeout = 5);
        if (!$fp) {
    
            echo "Ping URL ...... $url <br />\n ";
            echo "URL status ..... CLOSED <br />\n";
            echo "Error ............... $errstr ($errno)<br />\n";
    
         } 
    
        else {
            // $out = "GET / HTTP/1.1\r\n";
            // $out .= "$url\r\n";
            // $out .= "Connection: Close\r\n\r\n";
            //fwrite ($fp, $out);
            //displays header: 
               /*    
                while (!feof($fp)) {
                    echo fgets($fp, 128);
                 } 
            */
            // fclose($fp);
    
           echo "Ping URL ...... $url <br />\n  ";
            echo "URL status .... OPEN";
    
        }
    
    
     ?>