Michi: Webseite erreichbar, überprüfen!

Hallo, ich halte mich mal kurz und bündig.

Mit welchen PHP Befehl, kann ich die Existenz einer Webseite abfragen?

Also ob sie erreichbar ist, oder nicht?

Muss ich sie erst mit file_get_contents einlesen? Oder habe ich irgendwie die Möglichkeit, es einfach zu machen? Ich möchte nur abfragen ob sie erreichbar ist.

Gruß

Michi

  1. Hello,

    Dafür benötigst Du einen Head-Request.

    Das Ganze ist aber im Prinzip zweistufig. Zuerst muss man einen Socket zum entfernten Server aufbauen. Und dann kann man den eigentlichen HTTP/s-HEAD-Request ausführen.

    Der zurückgelieferte Status gibt dann Auskunft über den Erfolg, oder ob die Webseite woanders liegt, usw.

    Socket aufbauen mit fsockopen(). Dort findest Du auch Beispiele.

    Mit file_get_contents() geht das auch in einem Schritt. Du musst ja nur ein Byte der Datei des Dokumentes (Ressource) anfordern. Dann bekommst Du bei Erfolg die Header und das eine Byte.

    Das hat aber zwei Pferdefüße.

    • Die Wrapper für HTTP/s und file_get_contents müssen erlaubt sein.
    • Dir geht die genaue Information verloren, in welcher Stufe ggf. ein Fehler (z. B: Timeout) aufgetreten ist, also ob der Host nicht erreichbar war, oder der HTTP-Server, oder die Ressource selbst.
    • Du kannst die Timeouts nicht explizit setzen, wobei es da für file_get_contents() einen "Konext-Parameter" gibt. Der ist aber nur umständlich zu erstellen.

    Im Archiv findest Du auch ein paar tiefergehende Gedanken dazu. Da war wohl noch ein Schönheitsfehler drin, aber den findest Du bestimmt :-)
    Es gibt aber auch irgendwo eine überarbeitete Version mit substantiierten Fehlermeldung und auch für HTTPS, bzw, andere Ports als 80. Finde ich aber jetzt nicht.

    Das Prinzip sollte Dir aber klar werden können.

    Glück Auf
    Tom vom Berg

    --
    Es gibt nichts Gutes, außer man tut es!
    Das Leben selbst ist der Sinn.
  2. Mit welchen PHP Befehl, kann ich die Existenz einer Webseite abfragen? Also ob sie erreichbar ist, oder nicht?

    Bin zwar PHP-Laie, aber denke CURL ist für diesen Zweck völlig ausreichend und würde es mir sparen wollen, hierfür einen eigenen Socket aufzusetzen.

    Beispiel, via Suchmaschine gefunden.

    1. Hello,

      klingt fast genauso bequem, wie file_get_contents().

      Ist cURL innerhalb PHP auch so leisgtungsstark, wie standalone?
      Wie kommt man da an die Ergebnisse der einzelnen Stufen?

      Gelten für die PHP-cURL-Methoden auch die Einschränkungen der fopen-Wrapper, oder gibt es andere Restrictionen?

      Mit welchen PHP Befehl, kann ich die Existenz einer Webseite abfragen? Also ob sie erreichbar ist, oder nicht?

      Bin zwar PHP-Laie, aber denke CURL ist für diesen Zweck völlig ausreichend und würde es mir sparen wollen, hierfür einen eigenen Socket aufzusetzen.

      Beispiel, via Suchmaschine gefunden.

      Glück Auf
      Tom vom Berg

      --
      Es gibt nichts Gutes, außer man tut es!
      Das Leben selbst ist der Sinn.
      1. Hello,

        klingt fast genauso bequem, wie file_get_contents().

        Ist cURL innerhalb PHP auch so leisgtungsstark, wie standalone?
        Wie kommt man da an die Ergebnisse der einzelnen Stufen?

        Setze die Curl-Option CURLOPT_VERBOSE auf true:

        <?php 
        
        $dst_url = 'https://www.example.com';
        
        header( 'Content-Type text/plain' );
        
        error_reporting( E_ALL );
        ini_set( 'display_errors', 1);
        
        $ch = curl_init();
        
        curl_setopt( $ch, CURLOPT_URL, $dst_url );
        curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
        curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, 'HEAD' );
        curl_setopt( $ch, CURLOPT_NOBODY, true );
        
        
        ### So geht das:###
        curl_setopt( $ch, CURLOPT_VERBOSE, true ); 
        
        $result = curl_exec( $ch );
        
        print_r( curl_getinfo( $ch ) );
        
        curl_setopt( $ch, CURLOPT_VERBOSE, true );
        

        Die zusätzlichen Ausgaben sind dann:

        *   Trying 77.1.64.9:443...
        * TCP_NODELAY set
        * Connected to home.fastix.org (77.1.64.9) port 443 (#0)
        * ALPN, offering h2
        * ALPN, offering http/1.1
        * successfully set certificate verify locations:
        *   CAfile: /etc/ssl/certs/ca-certificates.crt
          CApath: /etc/ssl/certs
        * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
        * ALPN, server accepted to use http/1.1
        * Server certificate:
        *  subject: CN=code.fastix.org
        *  start date: Dec 22 19:54:50 2021 GMT
        *  expire date: Mar 22 19:54:49 2022 GMT
        *  subjectAltName: host "home.fastix.org" matched cert's "home.fastix.org"
        *  issuer: C=US; O=Let's Encrypt; CN=R3
        *  SSL certificate verify ok.
        
        > HEAD / HTTP/1.1
        
        Host: home.fastix.org
        Accept: */*
        
        * old SSL session ID is stale, removing
        * Mark bundle as not supporting multiuse
        < HTTP/1.1 200 OK
        < Date: Sat, 05 Feb 2022 15:29:59 GMT
        < Server: Apache/2.4.52
        < Last-Modified: Thu, 08 Oct 2020 07:41:54 GMT
        < ETag: "24f12-186-5b123f751f381"
        < Accept-Ranges: bytes
        < Content-Length: 390
        < Vary: Accept-Encoding
        < Permissions-Policy: interest-cohort=()
        < Content-Type: text/html; charset=UTF-8
        < 
        * Connection #0 to host home.fastix.org left intact
        
        1. Hello,

          Ist cURL innerhalb PHP auch so leisgtungsstark, wie standalone?
          Wie kommt man da an die Ergebnisse der einzelnen Stufen?

          Setze die Curl-Option CURLOPT_VERBOSE auf true:

          <?php 
          
          $dst_url = 'https://www.example.com';
          
          header( 'Content-Type text/plain' );
          
          error_reporting( E_ALL );
          ini_set( 'display_errors', 1);
          
          $ch = curl_init();
          
          curl_setopt( $ch, CURLOPT_URL, $dst_url );
          curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
          curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, 'HEAD' );
          curl_setopt( $ch, CURLOPT_NOBODY, true );
          
          
          ### So geht das:###
          curl_setopt( $ch, CURLOPT_VERBOSE, true ); 
          
          $result = curl_exec( $ch );
          
          print_r( curl_getinfo( $ch ) );
          
          curl_setopt( $ch, CURLOPT_VERBOSE, true );
          

          Die zusätzlichen Ausgaben sind dann:

          *   Trying 77.1.64.9:443...
          * TCP_NODELAY set
          * Connected to home.fastix.org (77.1.64.9) port 443 (#0)
          * ALPN, offering h2
          * ALPN, offering http/1.1
          * successfully set certificate verify locations:
          *   CAfile: /etc/ssl/certs/ca-certificates.crt
            CApath: /etc/ssl/certs
          * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
          * ALPN, server accepted to use http/1.1
          * Server certificate:
          *  subject: CN=code.fastix.org
          *  start date: Dec 22 19:54:50 2021 GMT
          *  expire date: Mar 22 19:54:49 2022 GMT
          *  subjectAltName: host "home.fastix.org" matched cert's "home.fastix.org"
          *  issuer: C=US; O=Let's Encrypt; CN=R3
          *  SSL certificate verify ok.
          > HEAD / HTTP/1.1
          Host: home.fastix.org
          Accept: */*
          
          * old SSL session ID is stale, removing
          * Mark bundle as not supporting multiuse
          < HTTP/1.1 200 OK
          < Date: Sat, 05 Feb 2022 15:29:59 GMT
          < Server: Apache/2.4.52
          < Last-Modified: Thu, 08 Oct 2020 07:41:54 GMT
          < ETag: "24f12-186-5b123f751f381"
          < Accept-Ranges: bytes
          < Content-Length: 390
          < Vary: Accept-Encoding
          < Permissions-Policy: interest-cohort=()
          < Content-Type: text/html; charset=UTF-8
          < 
          * Connection #0 to host home.fastix.org left intact
          

          Ich habe das jetzt leider noch nicht durchschaut.
          Wo landet diese zusätzliche Auskunft dann?
          Du hast die Aktivierung nach der Ausgabe mit print_r(); durchgeführt.

          Kann ich die in PHP auffangen?

          Glück Auf
          Tom vom Berg

          --
          Es gibt nichts Gutes, außer man tut es!
          Das Leben selbst ist der Sinn.
          1. curl_setopt( $ch, CURLOPT_VERBOSE, true );
            

            Du hast die Aktivierung nach der Ausgabe mit print_r(); durchgeführt.

            Editierungsfehler. Ich hatte die Zeile versehentlich zweimal eingefügt.

            Wo landet diese zusätzliche Auskunft dann?
            Kann ich die in PHP auffangen?

            Das Handbuch sagt:

            CURLOPT_VERBOSE: true, um ausführliche Informationen auszugeben, entweder nach STDERR oder in die mittels der Option CURLOPT_STDERR gewählte Datei.

            https://www.php.net/manual/de/function.curl-setopt.php

            Das Handbuch ist da leider „etwas undeutlich bis falsch“: Erwartet wird nicht etwa ein Dateiname sondern eine „Stream-Ressource“, also etwas, was man in Perl einen „Filehandler“ nennen würde. Siehe also fopen, tmpfile, fpassthru, fclose, … - Das steht (soweit zum „undeutlich“) aber in einem Kasten an einer „entfernten Stelle“:

            “Für die folgenden option-Parameter sollte value eine Stream-Resource sein, so wie sie z. B. mittels fopen() erstellt werden kann“

            (Falsch ist es aber auch: Es MUSS eine Stream-Resource sein.)

            So. Wir wissen genug. Exekutieren wir das in dem wir die Daten, statt diese sofort in den Fehlerkanal auszugeben, in einer temporären Datei speichern (und diese nach Ausgabe löschen):

            <?php 
            
            $dst_url = 'https://www.example.com';
            
            header( 'Content-Type text/plain' );
            
            error_reporting( E_ALL );
            ini_set( 'display_errors', 1);
            
            $ch = curl_init();
            $tempfile = tmpfile(); ### Erzeugen der temporären Datei
            
            curl_setopt( $ch, CURLOPT_URL, $dst_url );
            curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
            curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, 'HEAD' );
            curl_setopt( $ch, CURLOPT_NOBODY, true );
            
            
            ### So geht das:###
            curl_setopt( $ch, CURLOPT_VERBOSE, true ); 
            curl_setopt( $ch, CURLOPT_STDERR, $tempfile );
            
            $result = curl_exec( $ch );
            
            echo "-------------------------------" . PHP_EOL;
            echo "Daten aus der temporären Datei:" . PHP_EOL;
            echo "-------------------------------" . PHP_EOL;
            fpassthru( $tempfile );
            ### Das fclose löscht auch die temporäre Datei.
            ### Frühestmöglich ausführen. Grund im Handbuch:
            ### Wird das Skript unerwartet beendet,
            ### wird die temporäre Datei möglicherweise nicht gelöscht. 
            fclose( $tempfile ); 
            echo "-------------------------------" . PHP_EOL;
            echo PHP_EOL . "Gezeigt und gelöscht! Jetzt ..." . PHP_EOL;
            echo "-------------------------------" . PHP_EOL;
            echo "Daten von curl_getinfo:" . PHP_EOL;
            echo "-------------------------------" . PHP_EOL;
            print_r( curl_getinfo( $ch ) );
            echo "-------------------------------" . PHP_EOL;
            
            
            1. #!/bin/bash
              
              SERVER=${2}
              #SERVER='www.example.com/foo?bar#baz';
              SERVER=$(echo -n $SERVER | sed -e 's/[/?&#].*$//');
              
              PROTO=${1};
              if [ $PROTO != 'https' -a $PROTO != 'http' ]; then
                 echo "FEHLER: Falsches Protokoll."
                 exit 2;
              fi
              #PROTO='https';
              
              # echo $(wget -d --spider ${PROTO}://${SERVER}/ 2>&1 | grep 'HTTP.*[0-9][0-9][0-9]');
              t=$(wget -d --spider ${PROTO}://${SERVER} 2>&1 | grep 'HTTP.*[0-9][0-9][0-9]' | wc -l);
              if [ $t -eq 1 ]; then
                  echo "Erfolg: Der Server \"${SERVER}\" ist via \"${PROTO}\" erreichbar.";
                  exit 0;
              else
                  echo "FEHLER: Der Server \"${SERVER}\" ist via \"${PROTO}\" NICHT erreichbar.";
                  exit 1;
              fi
              

              Aufruf z.B. mit

              ./test.sh https 'www.example.com/foo&bar=baz#tok'
              

              Derlei könnte man z.B. als Cronjob ausführen und 'wegloggen' oder, im Falle eines Misserfolges, per Mail senden... Freilich bietet das noch viele schöne Möglichkeiten und SOLLS (deshalb habe ich das als „bad“ markiert) zum Anpassen, Verbessern und Basteln.

              So könnte man z.B. den Statuscode überprüfen. Hat man vergessen, seinen Hoster zu bezahlen kommt da z.B. oft 404 oder 403. Derzeit wird bei einem beliebigen Statuscode (siehe: grep 'HTTP.*[0-9][0-9][0-9]' | wc -l) die positive Antwort gegeben.

              Man könnte auch das Putzen des Servernamens weglassen… e.t.c,

            2. Hello,

              cURL in PHP kommt mir so vor, wie jQuery in Javascript. Da mag ich doch lieber "Banana" (entspricht Vanilla, aber für PHP) ;-)

              curl_setopt( $ch, CURLOPT_VERBOSE, true );
              

              Du hast die Aktivierung nach der Ausgabe mit print_r(); durchgeführt.

              Editierungsfehler. Ich hatte die Zeile versehentlich zweimal eingefügt.

              Wo landet diese zusätzliche Auskunft dann?
              Kann ich die in PHP auffangen?

              Das Handbuch sagt:

              CURLOPT_VERBOSE: true, um ausführliche Informationen auszugeben, entweder nach STDERR oder in die mittels der Option CURLOPT_STDERR gewählte Datei.

              https://www.php.net/manual/de/function.curl-setopt.php

              Das Handbuch ist da leider „etwas undeutlich bis falsch“: Erwartet wird nicht etwa ein Dateiname sondern eine „Stream-Ressource“, also etwas, was man in Perl einen „Filehandler“ nennen würde. Siehe also fopen, tmpfile, fpassthru, fclose, … - Das steht (soweit zum „undeutlich“) aber in einem Kasten an einer „entfernten Stelle“:

              “Für die folgenden option-Parameter sollte value eine Stream-Resource sein, so wie sie z. B. mittels fopen() erstellt werden kann“

              (Falsch ist es aber auch: Es MUSS eine Stream-Resource sein.)

              So. Wir wissen genug. Exekutieren wir das in dem wir die Daten, statt diese sofort in den Fehlerkanal auszugeben, in einer temporären Datei speichern (und diese nach Ausgabe löschen):

              <?php 
              
              $dst_url = 'https://www.example.com';
              
              header( 'Content-Type text/plain' );
              
              error_reporting( E_ALL );
              ini_set( 'display_errors', 1);
              
              $ch = curl_init();
              $tempfile = tmpfile(); ### Erzeugen der temporären Datei
              
              curl_setopt( $ch, CURLOPT_URL, $dst_url );
              curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
              curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, 'HEAD' );
              curl_setopt( $ch, CURLOPT_NOBODY, true );
              
              
              ### So geht das:###
              curl_setopt( $ch, CURLOPT_VERBOSE, true ); 
              curl_setopt( $ch, CURLOPT_STDERR, $tempfile );
              
              $result = curl_exec( $ch );
              
              echo "-------------------------------" . PHP_EOL;
              echo "Daten aus der temporären Datei:" . PHP_EOL;
              echo "-------------------------------" . PHP_EOL;
              fpassthru( $tempfile );
              ### Das fclose löscht auch die temporäre Datei.
              ### Frühestmöglich ausführen. Grund im Handbuch:
              ### Wird das Skript unerwartet beendet,
              ### wird die temporäre Datei möglicherweise nicht gelöscht. 
              fclose( $tempfile ); 
              echo "-------------------------------" . PHP_EOL;
              echo PHP_EOL . "Gezeigt und gelöscht! Jetzt ..." . PHP_EOL;
              echo "-------------------------------" . PHP_EOL;
              echo "Daten von curl_getinfo:" . PHP_EOL;
              echo "-------------------------------" . PHP_EOL;
              print_r( curl_getinfo( $ch ) );
              echo "-------------------------------" . PHP_EOL;
              
              

              Glück Auf
              Tom vom Berg

              --
              Es gibt nichts Gutes, außer man tut es!
              Das Leben selbst ist der Sinn.
      2. Hallo

        Gelten für die PHP-cURL-Methoden auch die Einschränkungen der fopen-Wrapper, oder gibt es andere Restrictionen?

        Ob es die selben oder eigene Restriktionen sind, kann ich nicht sagen, aber ja, es gibt offensichtlich Möglichkeiten, die cURL-Bibliothek für PHP an Requests nach außen zu hindern. Ich bin jedenfalls mal einem Webhoster „begegnet“, bei dem die „üblichen“ PHP-Kanäle nach außen dicht waren (fopen-Wrapper und ähnliche) und bei dem sich dann herausgestellt hat, dass cURL und die dazugehörige PHP-Bibliothek zwar installiert waren, aber auch über diese absolut kein Kontakt nach außen möglich war.

        Da hätten die die Funktion auch gleich ganz weg lassen können.

        Tschö, Auge

        --
        200 ist das neue 35.
  3. Wie schon von TS beschrieben wäre es ein „ressourcenschonender“ Weg, eine HEAD-Abfrage zu machen.

    Da Du aber binnen „nullkommafastnichts“ ohnehin auf die Idee kommen wirst, weitere Informationen erlangen zu wollen, empfehle ich Dir cUrl zu verwenden. Das geht etwa so:

    <?php 
    
    $dst_url = 'https://www.example.com';
    
    header( 'Content-Type text/plain' );
    
    error_reporting( E_ALL );
    ini_set( 'display_errors', 1);
    
    $ch = curl_init();
    
    curl_setopt( $ch, CURLOPT_URL, $dst_url );
    curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
    curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, 'HEAD' );
    curl_setopt( $ch, CURLOPT_NOBODY, true );
    
    $result = curl_exec( $ch );
    
    print_r( curl_getinfo( $ch ) );
    

    Ausgaben:

    Array
    (
        [url] => https://www.example.com/
        [content_type] => text/html; charset=UTF-8
        [http_code] => 200
        [header_size] => 352
        [request_size] => 53
        [filetime] => -1
        [ssl_verify_result] => 0
        [redirect_count] => 0
        [total_time] => 0.589923
        [namelookup_time] => 0.001856
        [connect_time] => 0.145835
        [pretransfer_time] => 0.446154
        [size_upload] => 0
        [size_download] => 0
        [speed_download] => 0
        [speed_upload] => 0
        [download_content_length] => 648
        [upload_content_length] => -1
        [starttransfer_time] => 0.589903
        [redirect_time] => 0
        [redirect_url] => 
        [primary_ip] => 93.184.216.34
        [certinfo] => Array
            (
            )
    
        [primary_port] => 443
        [local_ip] => 192.168.1.2
        [local_port] => 41472
        [http_version] => 3
        [protocol] => 2
        [ssl_verifyresult] => 0
        [scheme] => HTTPS
        [appconnect_time_us] => 446046
        [connect_time_us] => 145835
        [namelookup_time_us] => 1856
        [pretransfer_time_us] => 446154
        [redirect_time_us] => 0
        [starttransfer_time_us] => 589903
        [total_time_us] => 589923
    )
    

    Ich denke damit hast Du einen guten Startpunkt für weitere Überlegungen und Planungen - z.B. hinsichtlich der Frage, welche Informationen Du wie weiterverarbeiten willst. Wenn z.B. keine "primary_ip" geliefert wird hast Du einen DNS-Fehler, den Du weiter untersuchen musst bzw. kannst. Im Erfolgsfall könnten Dich die Zeitangaben interessieren…

    Mehr Informationen (z.B. Erklärungen zu den Items des Arrays) findest Du im PHP-Handbuch, hier mal ab curl_getinfo().

    Vorteil: cURL gibt es auch in zahlreichen weiteren Programmsprachen, sogar als eigenständiges Programm. Ich würde erwarten, dass jeder Hoster das entsprechende PHP-Modul installiert hat.

    Falls Du (was ich für einen Fehler halte) eine Testumgebung unter Windows benutzt (also Dein PHP unter Windows läuft solltest Du die Hinweise zur Installation lesen.