Fritz: HTTP/1.1 401 Unauthorized

Hallo,

ich möchte ein paar Bilder von einer anderen Seite per PHP abholen und lokal auf meinem Webspace speichern. Die Erlaubnis liegt vor. Folgendes kleines Script nutze ich

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

$url    = 'example.com/100_4871.JPG';
$img    = '100_4871.JPG';
$file   = file($url);
$result = file_put_contents($img, $file)
?>

Ich erhalte dabei folgende Fehlermeldung: failed to open stream: HTTP request failed! HTTP/1.1 401 Unauthorized

Ich denke, ich muss dem Script irgendwie die Login-Daten mit übergeben? die Frage ist nur wie?

  1. Hallo und guten Abend,

    ich möchte ein paar Bilder von einer anderen Seite per PHP abholen und lokal auf meinem Webspace speichern. Die Erlaubnis liegt vor. Folgendes kleines Script nutze ich

    <?php
    error_reporting(E_ALL);
    ini_set('display_errors', 1);
    
    $url    = 'example.com/100_4871.JPG';
    $img    = '100_4871.JPG';
    $file   = file($url);
    $result = file_put_contents($img, $file)
    ?>
    

    Du hast das Scheme vergessen: $url = 'http://example.com/100_4871.JPG

    Und mit der Zeile $file = file($url); erezugst Du ein Array mit den Textzeilen der Quelldatei. Bei Bildern ist das ziemlich unsinnig. Da nimmst Du besser file_get_contents() oder noch besser einen vollständigen File-Dialog mit fopen(), fread(), fclose(). Da kann man die Fehler besser behandeln. Und noch besser wäre im vorliegenden Fall fsockopen()- Denn dann könnte man auch die Timeouts für den Socket und das Lesen getrennt kontrollieren.

    [ich weiß, dass das bei file_get_contents() auch reingebastelt wurde ... ;-P]

    Und was die Zeile $result = file_put_contents($img, $file) bewirken soll, ist mir nicht einsichtig.

    Grüße
    TS

    --
    es wachse der Freifunk
    http://freifunk-oberharz.de
    1. Tach!

      Und was die Zeile $result = file_put_contents($img, $file) bewirken soll, ist mir nicht einsichtig.

      Das ist für den Teil "und lokal auf meinem Webspace speichern".

      dedlfix.

      1. Hallo und guten Abend,

        Und was die Zeile $result = file_put_contents($img, $file) bewirken soll, ist mir nicht einsichtig.

        Das ist für den Teil "und lokal auf meinem Webspace speichern".

        duck
        Ich bitte um Verzeihung. Ich hatte übersehen, dass file_put_contents() auch Arrays als Stream an den Kanal ausgeben kann.

        Grüße
        TS

        --
        es wachse der Freifunk
        http://freifunk-oberharz.de
  2. Tach!

    ich möchte ein paar Bilder von einer anderen Seite per PHP abholen und lokal auf meinem Webspace speichern.

    file() ist dazu aber nicht geeignet. Das liest Textdateien und gibt ein Array mit den Zeilen zurück. Du brauchst file_get_contents(), wenn du das auf diese einfache PHP-Weise machen möchtest.

    Ich denke, ich muss dem Script irgendwie die Login-Daten mit übergeben? die Frage ist nur wie?

    Auf der Handbuch-Seite zu dieser Funktion gibt es in den User-Kommentaren gleich im ersten ein Beispiel für Requests mit Nutzernamen. Du brauchst da nur die Struktur des Arrays als solches und vom inneren nur die header-Zeile, und davon nur den zweiten Teil.

    dedlfix.

    1. Hallo,

      Auf der Handbuch-Seite zu dieser Funktion gibt es in den User-Kommentaren gleich im ersten ein Beispiel für Requests mit Nutzernamen. Du brauchst da nur die Struktur des Arrays als solches und vom inneren nur die header-Zeile, und davon nur den zweiten Teil.

      wenn ich es richtig verstanden habe, müsste es so funktionieren.

      <?php
      error_reporting(E_ALL);
      ini_set('display_errors', 1);
      
      $https_user = "xxx";
      $https_password = "xxx";
      $https_server = "www.example.com";
      
      $opts = array('http' =>
        array(
          'method'  => 'POST',
          'header'  => "Content-Type: text/xml\r\n".
            "Authorization: Basic ".base64_encode("$https_user:$https_password")."\r\n"
        )
      );
      
      $context  = stream_context_create($opts);
      
      $bild = file_get_contents('https://www.example.com/100_4871.JPG'); file_put_contents('100_4871.JPG', $bild);
      
      ?>
      

      Allerdings bekomme ich genau den gleichen Fehler.

      1. Tach!

        wenn ich es richtig verstanden habe, müsste es so funktionieren.

        $opts = array('http' =>
          array(
            'method'  => 'POST',
            'header'  => "Content-Type: text/xml\r\n".
              "Authorization: Basic ".base64_encode("$https_user:$https_password")."\r\n"
          )
        );
        
        $context  = stream_context_create($opts);
        
        $bild = file_get_contents('https://www.example.com/100_4871.JPG'); 
        

        Ist es ein POST-Request? Ist der Body vom POST-Request (nicht der Body von der Response) text/xml? Der $context muss auch noch der Funktion file_get_contents() als Parameter übergeben werden.

        dedlfix.

        1. Hallo,

          Der $context muss auch noch der Funktion file_get_contents() als Parameter übergeben werden.

          Ok, ich habe file_get_contents den Wert $context mit übergeben

          $context  = stream_context_create($opts);
          $bild = file_get_contents('https://www.example.com/100_4871.JPG', $context); 
          file_put_contents('100_4871.JPG', $bild);
          

          Jetzt erhalte ich nur noch diese Fehlermeldung

          Warning: file_get_contents() expects parameter 2 to be boolean, resource given

          Zu deiner Frage

          Ist es ein POST-Request? Ist der Body vom POST-Request (nicht der Body von der Response) text/xml?

          Ich denke es ist text/xml denn ich erwarte ja ein Bild. Mehr steht im Dokument nicht drin.

          1. Tach!

            Warning: file_get_contents() expects parameter 2 to be boolean, resource given

            Du musst den Parameter an der richtigen Stelle übergeben. Der zweite Parameter gibt an, ob der include_path verwendet werden soll. Der dritte ist erst der Kontext. Parameter dürfen nicht zwischendrin ausgelassen werden.

            Zu deiner Frage

            Ist es ein POST-Request? Ist der Body vom POST-Request (nicht der Body von der Response) text/xml?

            Ich denke es ist text/xml denn ich erwarte ja ein Bild. Mehr steht im Dokument nicht drin.

            Sicher nicht. POST-Requests nimmt man, wenn man Daten hinschicken möchte. Hast du Daten hinzuschicken? Nein, keine (außer Header-Daten). Du möchtest vermutlich einen GET-Request absetzen. Der hat keinen Body, also auch keinen Content-Type. Die method-Zeile kannst du für GET auch weglassen, denn das ist der Default-Wert. Und läuft die Übertragung über HTTPS? Das musst du auch so nehmen, wie es bei dir ist. Wenn die URL https://... ist, muss das auch im Kontext-Array angepasst werden.

            dedlfix.

            1. Hallo,

              Sicher nicht. POST-Requests nimmt man, wenn man Daten hinschicken möchte. Hast du Daten hinzuschicken? Nein, keine (außer Header-Daten). Du möchtest vermutlich einen GET-Request absetzen. Der hat keinen Body, also auch keinen Content-Type. Die method-Zeile kannst du für GET auch weglassen, denn das ist der Default-Wert. Und läuft die Übertragung über HTTPS? Das musst du auch so nehmen, wie es bei dir ist. Wenn die URL https://... ist, muss das auch im Kontext-Array angepasst werden.

              OK, ich habe jetzt alles soweit gekürzt

              <?php
              error_reporting(E_ALL);
              ini_set('display_errors', 1);
              
              $http_user = "xx";
              $http_password = "xx";
              
              $opts = array('http' =>
                array(
                  'header'  => "Authorization: Basic ".base64_encode("$http_user:$http_password")."\r\n"
                )
              );
              
              $context  = stream_context_create($opts);
              $bild     = file_get_contents('http://www.example.com/100_4871.JPG', '', $context); 	
              
              ?>
              

              Erhalte allerdings die gleiche Fehlermeldung. Gebe ich das Passwort von Hand auf der Webseite ein komme ich problemlos in den internen Bereich und das Bild wird mit angezeigt.

              Die Übertragung läuft per http://

              1. Tach!

                OK, ich habe jetzt alles soweit gekürzt

                Das sieht jetzt soweit auch gut aus.

                Erhalte allerdings die gleiche Fehlermeldung. Gebe ich das Passwort von Hand auf der Webseite ein komme ich problemlos in den internen Bereich und das Bild wird mit angezeigt.

                Das ist schlecht. Läuft die Authentifizierung überhaupt über HTTP-Auth? Oder ist das eine Formular-Anmeldung mit Session und Session-Cookie oder dergleichen?

                dedlfix.

                1. Tach!

                  Läuft die Authentifizierung überhaupt über HTTP-Auth? Oder ist das eine Formular-Anmeldung mit Session und Session-Cookie oder dergleichen?

                  Das beantworte ich mir mal selbst: Ja, zumindest lässt der Statuscode 401 drauf schließen. Was also nun? Schau mal in den Browser, der hat Entwickler-Tools an Bord, und darin eine Network-Sektion. Schau dir da an, was der Browser macht, welche Header er sendet. Vielleicht will der Server ja keine Basic-Auth sondern irgendwas anderes. Der Browser kocht jedenfalls auch nur mit Wasser, und was der macht, kann man mit dem Stream-Kontext ziemlich genau nachbilden.

                  dedlfix.

                  1. Hallo,

                    Das beantworte ich mir mal selbst: Ja, zumindest lässt der Statuscode 401 drauf schließen. Was also nun? Schau mal in den Browser, der hat Entwickler-Tools an Bord, und darin eine Network-Sektion. Schau dir da an, was der Browser macht, welche Header er sendet. Vielleicht will der Server ja keine Basic-Auth sondern irgendwas anderes. Der Browser kocht jedenfalls auch nur mit Wasser, und was der macht, kann man mit dem Stream-Kontext ziemlich genau nachbilden.

                    ich sehe folgendes, keine Ahnung ob man damit etwas anfangen kann. Ich jedenfalls nicht

                    Alternativ-Text

                    Beim Login erhalte ich folgendes Fenster

                    Alternativ-Text

                    1. Tach!

                      ich sehe folgendes, keine Ahnung ob man damit etwas anfangen kann. Ich jedenfalls nicht

                      Alternativ-Text

                      Ich sehe was, und das ist NTLM. Das ist ein Windows-Anmeldeverfahren. Dabei kann ich dir nicht helfen. Es ist jedenfalls nicht so einfach wie Basic-Auth. Da gehen erst dreimal (geschätzt und sicher falsch) Request und Response durch die Gegend, bevor man da angemeldet ist.

                      Man kann es nachbauen, soviel weiß ich immerhin. Du kannst suchen, ob es eine Bibliothek gibt, mit der man PHP zum NTLM-Client machen kann. Die ersten paar Suchergebnisse zu PHP und NTLM beschrieben nur die Serverseite.

                      dedlfix.

                      1. Hallo und guten Abend,

                        Man kann es nachbauen, soviel weiß ich immerhin. Du kannst suchen, ob es eine Bibliothek gibt, mit der man PHP zum NTLM-Client machen kann. Die ersten paar Suchergebnisse zu PHP und NTLM beschrieben nur die Serverseite.

                        Wenn ich das richtig interpretiere, dann gibt's da was billiges von Apache:
                        http://blog.stefan-macke.com/2011/04/07/optional-ntlm-authentication-for-a-website-on-apache-with-php/

                        Oder man kann es wohl auch zu Fuß nachbauen:
                        https://loune.net/2007/10/simple-lightweight-ntlm-in-php/ und
                        https://loune.net/2009/09/ntlm-authentication-in-php-now-with-ntlmv2-hash-checking/

                        Grüße
                        TS

                        --
                        es wachse der Freifunk
                        http://freifunk-oberharz.de
                        1. Hallo,

                          Wenn ich das richtig interpretiere, dann gibt's da was billiges von Apache:
                          http://blog.stefan-macke.com/2011/04/07/optional-ntlm-authentication-for-a-website-on-apache-with-php/

                          klingt aber sehr kompliziert. Gibt es denn noch irgendwie einen anderen Weg die Bilder zu holen? Angenommen ich binde die Bilder mit einem absoluten Pfad bei auf der Seite ein, logg mich ein, dass ich die Bilder sehe. Habe ich dann irgendwie die Möglich an die Bilder zu kommen?

                          1. Tach!

                            klingt aber sehr kompliziert. Gibt es denn noch irgendwie einen anderen Weg die Bilder zu holen?

                            Wenn sie nur mit NTLM-Anmeldung freigegeben werden, dann musst du eben NTLM verwenden, wenn du rankommen möchtest. Ansonsten musst du entweder ein einfacheres Authentifizierungsverfahren (zusätzlich) im IIS konfigurieren oder die Bilder in einen Pfad ohne Auth verschieben.

                            dedlfix.