Kalle_B: Zufällige Passwörter generieren mit md5?

Hallöle,

in eine Tabelle mit einigen tausend Adressen möchte ich jeder Adresse einen eindeutigen Zugriffscode zuordnen.

Das Datenfeld ist UNIQUE und soll eine Zufallskombination von 8 Zahlen und Buchstaben erhalten, die man nicht "erraten" kann.

Ich könnte Zufallszahlen generieren, die mit md5 umwandeln. Aber dann habe ich 16 Zeichen. Ist es sinnvoll, daraus 8 zu entnehmen?

Oder gibt es eine bessere Methode?

LG, Kalle

  1. Hello,

    Ich könnte Zufallszahlen generieren, die mit md5 umwandeln. Aber dann habe ich 16 Zeichen. Ist es sinnvoll, daraus 8 zu entnehmen?

    Warum willst Du Deinen Schlüsselvorrat verringern, wenn es nicht notwendig ist?

    Erzeuge einfach mit einer Funktion Schlüssel z.B. aus der 64-Zeichen-Basis und versuche, sie in die Unique-Spalte einzufügen. Dies wiederholst Du dann eben solange, bis Du genügend Schlüssel hast.

    function get_random_str($lenmin,$lenmax,$extra='')
    {
      mt_srand ((double)microtime()*1000000);  ## ? ist das noch notwendig?
      $anzahl = mt_rand($lenmin,$lenmax);

    $zeichen="abcdefghijklmnopqrstuvwxyzäöüßABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ0123456789-+_&~.,!".$extra;

    $zufall="";

    $i=0;
      while($i<=$anzahl)
      {
        $zufall.=substr($zeichen,mt_rand(0,strlen($zeichen)-1),1);
        $i++;
      }
      return $zufall;
    }

    Wenn es nur ein paar Tausend sind, kannst Du ja auch ein Array füllen damit.

    Liebe Grüße aus dem schönen Oberharz

    Tom vom Berg

    --
    Nur selber lernen macht schlau
    http://bergpost.annerschbarrich.de
    1. n'abend,

      mt_srand ((double)microtime()*1000000);  ## ? ist das noch notwendig?

      laut Doku nicht: »Hinweis: Seit PHP 4.2.0 besteht keine Notwendigkeit mehr, den Zufallsgenerator für Zahlen mit srand() oder mt_srand() zu füttern, das geschieht nun automatisch.«

      $zeichen="abcdefghijklmnopqrstuvwxyzäöüßABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ0123456789-+_&~.,!".$extra;

      [...]

      $zufall.=substr($zeichen,mt_rand(0,strlen($zeichen)-1),1);

      Ich hab das spaßeshalber mal mit einer rein auf array-Funktionen setzenden Lösung verglichen, die etwa das gleiche ermöglich wie deine String-basierte. Das (etwas überraschende) Resultat:

      randomString() took 0.282233953476 seconds and generated 10000 unique strings in 10000 runs
      get_random_str() took 0.887847900391 seconds and generated 10000 unique strings in 10000 runs

      <?php  
        
      /**  
       * Generiere zufällige (alphanumerische) Zeichenfolge aus den Bereichen a-z, A-Z, 0-9  
       * @param integer $min minimale Anzahl an Zeichen  
       * @param integer $max maximale Anzahl an Zeichen (optional)  
       * @param array $additionalCharacters zusätzliche  
       * @return string zufällige Zeichenkette  
       */  
      function randomString( $min, $max=null, $additionalCharacters=array() )  
      {  
        // baue alphanumerisches character-array nur einmal für alle folgenden aufrufe  
        static $characters = null;  
        if( $characters === null )  
        {  
          $characters = array_merge(  
            range( 'a', 'z' ), // kleinbuchstaben  
            range( 'A', 'Z' ), // grossbuchstaben  
            range( 0, 9 ) // zahlen  
          );  
        }  
      	  
        // füge zusätzliche zeichen ein  
        $c = $additionalCharacters ? array_merge( $characters, $additionalCharacters ) : $characters;  
      	  
        // ermittle länge des zufallstrings  
        $length = is_numeric($max) && $min != $max ? mt_rand( $min, $max ) : $min;  
        
        // ermittle zufällige indexe aus dem character-array  
        $indexes = array_rand( $c, $length );  
        
        // ziehe zeichen zu jeweiligem index aus dem character-array  
        $t = array();  
        foreach( $indexes as $i )  
          $t[] = $c[ $i ];  
        
        // füge einzelne zeichen zu einem string zusammen  
        return join( $t );  
      }  
        
      echo '<pre>';  
        
      $runs = 10000;  
      $start = microtime(true);  
        
      $t = array();  
      for( $i=0; $i < $runs; $i++ )  
      	$t[] = randomString( 10 );  
        
      $end = microtime(true);  
      echo 'randomString() took ', $end - $start, ' seconds and generated ', count( array_unique( $t ) ), ' unique strings in ', $runs, ' runs', "\n";  
        
        
      function get_random_str($lenmin,$lenmax,$extra='')  
      {  
        mt_srand ((double)microtime()*1000000);  ## ? ist das noch notwendig?  
        $anzahl = mt_rand($lenmin,$lenmax);  
        
        $zeichen="abcdefghijklmnopqrstuvwxyzäöüßABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ0123456789-+_&~.,!".$extra;  
        
        $zufall="";  
        
        $i=0;  
        while($i<=$anzahl)  
        {  
          $zufall.=substr($zeichen,mt_rand(0,strlen($zeichen)-1),1);  
          $i++;  
        }  
        return $zufall;  
      }  
        
      $start = microtime(true);  
        
      $t = array();  
      for( $i=0; $i < $runs; $i++ )  
        $t[] = get_random_str( 10, 10 );  
        
      $end = microtime(true);  
      echo 'get_random_str() took ', $end - $start, ' seconds and generated ', count( array_unique( $t ) ), ' unique strings in ', $runs, ' runs', "\n";  
        
      echo '</pre>';  
        
      ?>
      

      Wenn man den gleichen Zeichenvorrat haben möchte (ohne ihn fest einzuprogrammieren), sieht das auch schon wieder anders aus:

      randomString() took 0.518404960632 seconds and generated 10000 unique strings in 10000 runs
      get_random_str() took 0.823408842087 seconds and generated 10000 unique strings in 10000 runs

      Bei folgendem Aufruf:
      randomString( 10, null, array( 'ä','ö','ü','ß','Ä','Ö','Ü','-','+','_','&','~','.',',','!' ) );

      weiterhin schönen abend...

      --
      #selfhtml hat ein Forum?
      sh:( fo:# ch:# rl:| br:> n4:& ie:{ mo:} va:) de:] zu:} fl:( ss:? ls:[ js:|
      1. Hello,

        Wenn man den gleichen Zeichenvorrat haben möchte (ohne ihn fest einzuprogrammieren), sieht das auch schon wieder anders aus:

        randomString() took 0.518404960632 seconds and generated 10000 unique strings in 10000 runs
        get_random_str() took 0.823408842087 seconds and generated 10000 unique strings in 10000 runs

        Bei folgendem Aufruf:
        randomString( 10, null, array( 'ä','ö','ü','ß','Ä','Ö','Ü','-','+','_','&','~','.',',','!' ) );

        Vielen Dank für die Bereicherung der Scriptsammlung :-)

        Das mit der static-Variable für das Array finde ich gut.
        Auf diese Idee war ich noch gar nicht gekommen.

        Liebe Grüße aus dem schönen Oberharz

        Tom vom Berg

        --
        Nur selber lernen macht schlau
        http://bergpost.annerschbarrich.de
        1. n'abend,

          Vielen Dank für die Bereicherung der Scriptsammlung :-)

          Vier PHP-Doku-Seiten und 10 Min. Tipperei bedürfen keines Dankes.

          Das mit der static-Variable für das Array finde ich gut.
          Auf diese Idee war ich noch gar nicht gekommen.

          Vorweg: Es macht niemals Sinn unveränderlichen Inhalt andauernd neu zu berechnen. Einmal eine (so genannte) Look-Up-Table bauen und dann die vorteile einer Hash-Map nutzen...

          Die static Variable ist eigentlich nur ein Behelfsmittel. Wir leben im Jahr 2009, können OOP und sollten es eigentlich besser hinbekommen. Um das mal kurz zu demonstrieren, habe ich weitere 15 Minuten aufgebracht.

          RandomStringGenerator::generator() took 0.263427019119 seconds and generated 10000 unique strings in 10000 runs
          UniqueRandomStringGenerator::generator() took 0.33697104454 seconds and generated 10000 unique strings in 10000 runs
          randomString() took 0.812494039536 seconds and generated 10000 unique strings in 10000 runs
          get_random_str() took 0.871380090714 seconds and generated 10000 unique strings in 10000 runs

          <?php  
            
          /**  
           * Random String Generation  
           * @package examples  
           * @author Rodney Rehm  
           */  
          class RandomStringGenerator  
          {  
            /**  
             * language for random string  
             * @var array  
             */  
            protected $characters = array();  
            
            /**  
             * Create a new RandomStringGenerator instance  
             * @param boolean $alphanumeric add alphanumeric characters to base  
             * @return void  
             * @uses addAlphanumericCharacters() if $alphanumeric was set to true  
             */  
            public function __construct( $alphanumeric=true )  
            {  
              if( $alphanumeric )  
                $this->addAlphanumericCharacters();  
            }  
            
            /**  
             * add alphanumeric characters ( a-z, A-Z, 0-9 ) to base  
             * @return void  
             * @uses addCharacters() to merge new characters into base  
             */  
            public function addAlphanumericCharacters()  
            {  
              $characters = array_merge(  
                range( 'a', 'z' ),  
                range( 'A', 'Z' ),  
                range( '0', '9' )  
              );  
            
              $this->addCharacters( $characters );  
            }  
            
            /**  
             * Add characters to generator's character base.  
             * Merges an array into the character base.  
             * Adds a single character to the base.  
             * Splits a string into single characters and adds them to the base  
             * @param string|array $characters characters to add  
             * @return void  
             * @uses updateCharacters() to run checks on the character base  
             */  
            public function addCharacters( $characters )  
            {  
              switch( true )  
              {  
                // arrays can simply be merged into the base  
                case is_array( $characters ):  
                  $this->characters = array_merge( $this->characters, $characters );  
                break;  
            
                case is_string( $characters ):  
                  // simply add a single character to the base  
                  if( strlen( $characters ) === 1 ) // strlen is not multibyte safe  
                    $this->characters[] = $characters;  
            
                  else  
                  {  
                    // split string into array of characters  
                    $characters = preg_split('//', $characters, -1, PREG_SPLIT_NO_EMPTY);  
                    $this->addCharacters( $characters );  
                    return;  
                  }  
                break;  
              }  
            
              // ensure the character base satisfies the requirements  
              $this->updateCharacters();  
            }  
            
            /**  
             * ensure the character base satisfies the requirements,  
             * like each character occuring only once.  
             * @return void  
             */  
            protected function updateCharacters()  
            {  
              $this->characters = array_unique( $this->characters );  
            }  
            
            /**  
             * Generate a random string  
             *  
             * @param integer $min minimum length of generated string  
             * @param integer $max maximum length of string, defaults to $min if omitted  
             * @return string random string  
             */  
            public function generate( $min, $max=null )  
            {  
              // ermittle länge des zufallstrings  
              $length = is_numeric($max) && $min != $max ? mt_rand( $min, $max ) : $min;  
            
              // ermittle zufällige indexe aus dem character-array  
              $indexes = array_rand( $this->characters, $length );  
            
              // ziehe zeichen zu jeweiligem index aus dem character-array  
              $t = array();  
              foreach( $indexes as $i )  
                $t[] = $this->characters[ $i ];  
            
              return join( $t );  
            }  
          }  
            
          /**  
           * Unique Random String Generation  
           * @package examples  
           * @author Rodney Rehm  
           */  
          class UniqueRandomStringGenerator extends RandomStringGenerator  
          {  
            /**  
             * list of already generated strings  
             * @var array  
             */  
            protected $previous = array();  
            
            /**  
             * Generate a random string  
             *  
             * @param integer $min minimum length of generated string  
             * @param integer $max maximum length of string, defaults to $min if omitted  
             * @return string random string  
             * @uses $previous to remember generated strings and check for duplicates  
             */  
            public function generate( $min, $max=null )  
            {  
              // generate random string  
              $t = parent::generate( $min, $max );  
            
              // check if generated string is unqiue  
              if( array_key_exists( $t, $this->previous ) )  
                return $this->generate( $min, $max );  
            
              $this->previous[ $t ] = 1;  
            
              return $t;  
            }  
          }  
            
          echo '<pre>';  
            
          $runs = 10000;  
            
          $start = microtime(true);  
            
          $generator = new RandomStringGenerator();  
          $generator->addCharacters( 'ä' );  
          $generator->addCharacters( array( 'ö','ü','ß','Ä','Ö','Ü','-','+','_','&' ) );  
          $generator->addCharacters( '~.,!' );  
            
          $t = array();  
          for( $i=0; $i < $runs; $i++ )  
          	$t[] = $generator->generate( 10 );  
            
          $end = microtime(true);  
          echo 'RandomStringGenerator::generator() took ', $end - $start, ' seconds and generated ', count( array_unique( $t ) ), ' unique strings in ', $runs, ' runs', "\n";  
            
          $start = microtime(true);  
            
          $generator = new UniqueRandomStringGenerator();  
          $generator->addCharacters( 'ä' );  
          $generator->addCharacters( array( 'ö','ü','ß','Ä','Ö','Ü','-','+','_','&' ) );  
          $generator->addCharacters( '~.,!' );  
            
          $t = array();  
          for( $i=0; $i < $runs; $i++ )  
          	$t[] = $generator->generate( 10 );  
            
          $end = microtime(true);  
          echo 'UniqueRandomStringGenerator::generator() took ', $end - $start, ' seconds and generated ', count( array_unique( $t ) ), ' unique strings in ', $runs, ' runs', "\n";  
            
          echo '</pre>';  
            
          ?>  
          
          

          weiterhin schönen abend...

          --
          #selfhtml hat ein Forum?
          sh:( fo:# ch:# rl:| br:> n4:& ie:{ mo:} va:) de:] zu:} fl:( ss:? ls:[ js:|
      2. echo $begrüßung;

        »   mt_srand ((double)microtime()*1000000);  ## ? ist das noch notwendig?
        laut Doku nicht: »Hinweis: Seit PHP 4.2.0 besteht keine Notwendigkeit mehr, den Zufallsgenerator für Zahlen mit srand() oder mt_srand() zu füttern, das geschieht nun automatisch.«

        Obendrein ist das für sicherheitskritische Anwendungen kontraproduktiv. Das Initialisieren des Zufallszahlengenerators mit einem definierten Wert ergibt ein definiertes Ergebnis. Wenn der Wert relativ leicht erratbar ist, dann ist das Ergebnis ...

        echo "$verabschiedung $name";

      3. Hello Globe, hello@all

        ich bin das nochmal durchgegangen, habe den Längenfehler in meiner Triviallösung beseitigt und die while()-Schleife gegen eine for()-Schleife ausgetauscht. der Test auf dem Wampp ergab dann aber merkwürdige Ergebnisse:

        <?php

        /**
         * author: globe
         * lector: tom
         * siehe http://forum.de.selfhtml.org/my/?t=187722&m=1248486

        #------------------------------------------------------------------------------
         #
         # Generiere zufällige (alphanumerische) Zeichenfolge aus den Bereichen a-z, A-Z, 0-9
         # @param integer $min minimale Anzahl an Zeichen
         # @param integer $max maximale Anzahl an Zeichen (optional)
         # @param array $additionalCharacters zusätzliche
         # @return string zufällige Zeichenkette
         */
        function randomString( $min, $max=null, $additionalCharacters=array() )
        {
            // baue alphanumerisches character-array nur einmal für alle folgenden aufrufe
            static $characters = null;

        if( $characters === null )
            {
                $characters = array_merge(
                    range( 'a', 'z' ), // kleinbuchstaben
                    range( 'A', 'Z' ), // grossbuchstaben
                    range( 0, 9 ) // zahlen
                );
            }

        // füge zusätzliche zeichen ein
            $c = $additionalCharacters ? array_merge( $characters, $additionalCharacters ) : $characters;

        // ermittle länge des zufallstrings
            $length = is_numeric($max) && $min != $max ? mt_rand( $min, $max ) : $min;

        // ermittle zufällige indexe aus dem character-array
            $indexes = array_rand( $c, $length );

        // ziehe zeichen zu jeweiligem index aus dem character-array
            $t = array();

        foreach( $indexes as $i )
            {
                $t[] = $c[ $i ];
            }

        // füge einzelne zeichen zu einem string zusammen
            return join( $t );
        }

        #------------------------------------------------------------------------------

        function get_random_str($lenmin, $lenmax, $extra='')
        {
          #mt_srand ((double)microtime()*1000000);  ## ? ist das noch notwendig?
          $anzahl = mt_rand($lenmin,$lenmax);

        $zeichen="abcdefghijklmnopqrstuvwxyzäöüßABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜ0123456789-+_&~.,!".$extra;

        $zufall="";

        $i=0;
          for ($i = 0; $i < $anzahl; $i++)
          {
            $zufall .= substr($zeichen, mt_rand(0,strlen($zeichen)-1),1);
          }

        return $zufall;
        }
        #==============================================================================

        php main

        #==============================================================================
        echo '<pre>';

        $runs = 10000;

        $start = microtime(true);

        $t = array();
        for( $i=0; $i < $runs; $i++ )
        {
            $t[] = randomString( 10 );
        }

        $end = microtime(true);
        echo 'randomString() took ', $end - $start, ' seconds and generated ', count( array_unique( $t ) ), ' unique strings in ', $runs, ' runs', "\n";

        #-----------------------

        $start = microtime(true);

        $t = array();
        for( $i=0; $i < $runs; $i++ )
        {
            $t[] = get_random_str( 10, 10 );
        }

        $end = microtime(true);
        echo 'get_random_str() took ', $end - $start, ' seconds and generated ', count( array_unique( $t ) ), ' unique strings in ', $runs, ' runs', "\n";

        echo '</pre>';

        ?>

        1. Durchlauf:

        randomString() took 0.505483865738 seconds and generated 559 unique strings in 10000 runs
            get_random_str() took 0.520390033722 seconds and generated 10000 unique strings in 10000 runs

        2. Durchlauf:

        randomString() took 0.470019102097 seconds and generated 559 unique strings in 10000 runs
            get_random_str() took 0.521300077438 seconds and generated 10000 unique strings in 10000 runs

        3. Durchlauf

        randomString() took 0.528935909271 seconds and generated 559 unique strings in 10000 runs
           get_random_str() took 0.467758178711 seconds and generated 10000 unique strings in 10000 runs

        Wieso erzeiugt die Array-Lösung bei mir immer 559 unique Strings?

        Das Geheimnis wird wohl in array_rand() liegen.
        Ich habe noch nicht in den Quelltext geschaut, wie das nun wieder den Parameter num_req umsetzt.
        http://de3.php.net/manual/en/function.array-rand.php

        Ich hätte intuitiv das gesamte Array verwürfelt und dann nur die $len Stück in der foreach-Schliefe ausgeschnitten, also foreach bei $len abgebrochen.

        Der Bremser in der String-Lösung war aber eindeutig die while()-Schleife

        [Zur OOP-Lösung hätte ich dann auch noch einige Frägelchen. Allerdings habe ich es dort mit meinen Umbauten im Moment nur geschafft, dass sie mir immer den Apachen runterfährt *g*. dauert also noch, weil mich DIE Ursache nun erstmal interessiert]

        Liebe Grüße aus dem schönen Oberharz

        Tom vom Berg

        --
        Nur selber lernen macht schlau
        http://bergpost.annerschbarrich.de
        1. n'abend,

          1. Durchlauf:

          randomString() took 0.505483865738 seconds and generated 559 unique strings in 10000 runs
              get_random_str() took 0.520390033722 seconds and generated 10000 unique strings in 10000 runs

          1. Durchlauf:

          randomString() took 0.470019102097 seconds and generated 559 unique strings in 10000 runs
              get_random_str() took 0.521300077438 seconds and generated 10000 unique strings in 10000 runs

          1. Durchlauf

          randomString() took 0.528935909271 seconds and generated 559 unique strings in 10000 runs
             get_random_str() took 0.467758178711 seconds and generated 10000 unique strings in 10000 runs

          Wenn ich dein Script bei mir ausführe:

          randomString() took 0.323642969131 seconds and generated 10000 unique strings in 10000 runs
          get_random_str() took 0.680213928223 seconds and generated 10000 unique strings in 10000 runs

          Wieso erzeiugt die Array-Lösung bei mir immer 559 unique Strings?

          Das kann ich - da es bei mir nicht vorkommt - nicht nachvollziehen.

          Das Geheimnis wird wohl in array_rand() liegen.
          Ich habe noch nicht in den Quelltext geschaut, wie das nun wieder den Parameter num_req umsetzt.
          http://de3.php.net/manual/en/function.array-rand.php

          $num_req spezifiziert - wie die Doku schon sagt - die (maximale) Anzahl der Indexe, die man zurück bekommen möchte.

          Ich hätte intuitiv das gesamte Array verwürfelt und dann nur die $len Stück in der foreach-Schliefe ausgeschnitten, also foreach bei $len abgebrochen.

          Das wäre sicher auch eine Möglichkeit gewesen. Stellt sich die Frage wie das mit der Ausführungszeit ausschaut. Kannst du ja mal ausprobieren ;)

          Der Bremser in der String-Lösung war aber eindeutig die while()-Schleife

          Wusstest du, dass du auf einen String wie auf ein Array von Zeichen zugreifen kannst?

          aus substr($zeichen, mt_rand(0,strlen($zeichen)-1),1) kann man einfachst $strlen = strlen($zeichen); $zeichen[ mt_rand( 0, $strlen ) -1 ] machen. Bemerke auch, dass ich das strlen() herausgezogen habe. Das ist wieder so ein Fall von "unveränderliche Werte andauernd neu berechnen" - vollkommen unnötig.

          weiterhin schönen abend...

          --
          #selfhtml hat ein Forum?
          sh:( fo:# ch:# rl:| br:> n4:& ie:{ mo:} va:) de:] zu:} fl:( ss:? ls:[ js:|
          1. Hello,

            Das Geheimnis wird wohl in array_rand() liegen.
            Ich habe noch nicht in den Quelltext geschaut, wie das nun wieder den Parameter num_req umsetzt.
            http://de3.php.net/manual/en/function.array-rand.php

            $num_req spezifiziert - wie die Doku schon sagt - die (maximale) Anzahl der Indexe, die man zurück bekommen möchte.

            Ich befürchte, dass das nur die Anzahl der Zeichen angibt, die in die Auswahl einbezogen werden.
            Ich teste das Script nochmal auf meinem Debian-Testserver. Muss nur die Platte erst ausgraben. Da steckt gerade noch ne kaputte Suse 11 drin.

            #####################################################
              Könnten ja auch andere Tester nochmal versuchen...
            #####################################################

            Ich hätte intuitiv das gesamte Array verwürfelt und dann nur die $len Stück in der foreach-Schliefe ausgeschnitten, also foreach bei $len abgebrochen.

            Das wäre sicher auch eine Möglichkeit gewesen. Stellt sich die Frage wie das mit der Ausführungszeit ausschaut. Kannst du ja mal ausprobieren ;)

            *grummel* Ok, mach ich

            Der Bremser in der String-Lösung war aber eindeutig die while()-Schleife

            Wusstest du, dass du auf einen String wie auf ein Array von Zeichen zugreifen kannst?

            Funktioniert der Index-Operator denn jetzt auch für UTF-8 codierte Strings?

            weiterhin schönen abend...

            Und sach doch nich immer Arschloch zu mir :-P

            Liebe Grüße aus dem schönen Oberharz

            Tom vom Berg

            --
            Nur selber lernen macht schlau
            http://bergpost.annerschbarrich.de
          2. echo $begrüßung;

            aus substr($zeichen, mt_rand(0,strlen($zeichen)-1),1) kann man einfachst $strlen = strlen($zeichen); $zeichen[ mt_rand( 0, $strlen ) -1 ] machen.

            Hier musst du nochmal nachbessern. Ein String hat keinen Index -1.

            echo "$verabschiedung $name";

            1. Hello,

              aus substr($zeichen, mt_rand(0,strlen($zeichen)-1),1) kann man einfachst $strlen = strlen($zeichen); $zeichen[ mt_rand( 0, $strlen ) -1 ] machen.

              Hier musst du nochmal nachbessern. Ein String hat keinen Index -1.

              Das ist sowieso noch alles Panne, weil die Funktion nicht multibytefest ist.
              Das müsste da also auf jeden Fall noch rein.

              Liebe Grüße aus dem schönen Oberharz

              Tom vom Berg

              --
              Nur selber lernen macht schlau
              http://bergpost.annerschbarrich.de
            2. n'abend,

              Hier musst du nochmal nachbessern. Ein String hat keinen Index -1.

              oller besserwisser.. :P

              $strlen = strlen($zeichen); $zeichen[ mt_rand( 0, $strlen -1 ) ]

              weiterhin schönen abend...

              --
              #selfhtml hat ein Forum?
              sh:( fo:# ch:# rl:| br:> n4:& ie:{ mo:} va:) de:] zu:} fl:( ss:? ls:[ js:|
              1. Hello,

                Hier musst du nochmal nachbessern. Ein String hat keinen Index -1.

                oller besserwisser.. :P

                Genau! Dedlfix kann auch nur nörgeln :-)

                Ich zergrübel mir jetzt schon die ganze Zeit den Kopf, was man mit seinen Scripten bezüglich der Multibytefestigkeit anstellen kann, damit die das alleine merken,

                • wie sie (vom Weiternutzer) abgespeichert wurden (ISO oder UTF-8 oder ...)
                • in welcher Umgebung sie laufen                  (was liefert der Webserver aus, was erwartet er?)
                • was sie an Eingangsmaterial bekommen
                • was sie an Ausgangsmaterial liefern sollen

                und wie man es in einer Superklasse verdrahten könnte, von der dann alle anderen abgeleitet werden MÜSSEN

                Liebe Grüße aus dem schönen Oberharz

                Tom vom Berg

                --
                Nur selber lernen macht schlau
                http://bergpost.annerschbarrich.de
                1. n'abend,

                  Der "Array Access For Strings" ist eine PHP-interne Geschichte, die wir nicht nachträglich Multibyte-fest bekommen. Mein Hinweis auf diese Technik ist also mehr theoretischer als praktischer Natur.

                  Ich zergrübel mir jetzt schon die ganze Zeit den Kopf, was man mit seinen Scripten bezüglich der Multibytefestigkeit anstellen kann, damit die das alleine merken,

                  Ich setze zwischenzeitlich überall nur noch auf UTF-8. Mit Multibyte String ist das auch kein Problem. Da ich keine Tools für die Masse schreibe, also Geschichten für eine möglichst breite Palette an unterschiedlichen Umgebungen und Bedürfnissen, interessiert mich das alles auch gar nicht mehr. Ich erlaube mir die Arroganz für meinen Kram gewisse Module und Konfigurationen vorauszusetzen.

                  • wie sie (vom Weiternutzer) abgespeichert wurden (ISO oder UTF-8 oder ...)

                  UTF-8 zur Rettung der Welt!

                  • in welcher Umgebung sie laufen                  (was liefert der Webserver aus, was erwartet er?)

                  Der Webserver will UTF-8 ausliefern. In Formularen kann man den das erwartete Encoding spezifizieren (accept-charset).

                  und wie man es in einer Superklasse verdrahten könnte, von der dann alle anderen abgeleitet werden MÜSSEN

                  Um, wenn denn der unwahrscheinliche Fall nativen Unicodes in PHP eintritt, leicht umsteigen zu können, zwischenzeitlich aber trotzdem "gescheit" arbeiten zu können, habe ich sämtliche von mir verwendeten String-Funktionen in einer abstrakten Klasse "Strings" gewrappt. In aller Regel sind das gewrappte MBString-Funktion, oder eben UTF8 spezifische Nachbauten von Dingen, die MBString so nicht bietet. (neben weiterer UTF8-spezifischer Funktionen). Da ist aber auch (genehmigter :) Drittcode mit bei, weshalb sich das nich mal eben schnell veröffentlichen lässt.

                  weiterhin schönen abend...

                  --
                  #selfhtml hat ein Forum?
                  sh:( fo:# ch:# rl:| br:> n4:& ie:{ mo:} va:) de:] zu:} fl:( ss:? ls:[ js:|
                  1. Hello,

                    bin inzwischen ein Stückchen weiter mit der Überlegung.

                    <?php   ### saved_as_utf.php ###

                    $teststring  = 'äöü';                 ## Testliteral
                    $strlen_byte = strlen($teststring);   ## Stringlänge in Bytes ermitteln.

                    if ( $strlen_byte == 3 )
                    {
                        header('Content-Type: text/html; charset=ISO-8859-1');
                    }
                    elseif ( $strlen_byte == 6 )
                    {
                        header('Content-Type: text/html; charset=UTF-8');
                    }

                    echo "<pre>\r\n";
                    echo "$teststring ist " . strlen($teststring) . " Zeichen lang\r\n";
                    echo "</pre>\r\n";

                    ?>

                    Dieses Scriptlein kann man nun in ISO8859 (ANSI ?) oder in UTF-8 abspeichern und es merkt dann, wie es der Weiterverwender abgespeichert hat.

                    Das ist mir aber noch zu grob, obwohl es für die Praxis wohl reichen würde.

                    Liebe Grüße aus dem schönen Oberharz

                    Tom vom Berg

                    --
                    Nur selber lernen macht schlau
                    http://bergpost.annerschbarrich.de
                    1. n'abend,

                      Dieses Scriptlein kann man nun in ISO8859 (ANSI ?) oder in UTF-8 abspeichern und es merkt dann, wie es der Weiterverwender abgespeichert hat.

                      Deine Tests (wenn auch nicht 100% akkurat) mögen zwar interessant sein, lösen aber das Problem nicht. Andauernde (sogar noch interne) Prüfungen des Zeichensatzes und Konvertierungen will man vermeiden. Das kostet nur unnötig Rechenleistung, Source-Code und vor allem Nerven.

                      Entscheide dich für einen Zeichensatz - und bleib dabei.

                      weiterhin schönen abend...

                      --
                      #selfhtml hat ein Forum?
                      sh:( fo:# ch:# rl:| br:> n4:& ie:{ mo:} va:) de:] zu:} fl:( ss:? ls:[ js:|
                      1. Hello,

                        Entscheide dich für einen Zeichensatz - und bleib dabei.

                        Das ist das Problem. Es ist nicht meine Entscheidung, was ein Verwender nachher im Einsatz hat.

                        Die meisten Scripte müssen sowohl auf Servern laufen, die ISO-8859-1 nutzen, als auch auf solchen, die UTF-8 benutzten.

                        Ich möchte die Scripte daher so absichern, dass sie sich entweder weigern, falsch eingerichet zu arbeiten oder eben besser, nach Möglichkiet auf die (Fehl-)Einrichtung reagieren, zumindest also (im Installationsmodus) gezielt Anweisung geben, was zu ändern ist.

                        Dass ich nun gerade durch den Zufallsgenerator wieder auf diese Aufgabe vom Zettel gestupst werden, ist eben Zufall *gg*

                        Liebe Grüße aus dem schönen Oberharz

                        Tom vom Berg

                        --
                        Nur selber lernen macht schlau
                        http://bergpost.annerschbarrich.de
                        1. echo $begrüßung;

                          » Entscheide dich für einen Zeichensatz - und bleib dabei.
                          Das ist das Problem. Es ist nicht meine Entscheidung, was ein Verwender nachher im Einsatz hat.

                          Dann schreib ihm ein HowTo-Dokument. Wenn er das nicht beachtet, ist es nicht mehr dein Problem.

                          Die meisten Scripte müssen sowohl auf Servern laufen, die ISO-8859-1 nutzen, als auch auf solchen, die UTF-8 benutzten.

                          Was der Server nutzt ist egal. Hautpsache, er kann dazu bewegt werden, Content-Type-Header mit selbst festgelegter charset-Angabe auszuliefern.

                          Ich möchte die Scripte daher so absichern, dass sie sich entweder weigern, falsch eingerichet zu arbeiten oder eben besser, nach Möglichkiet auf die (Fehl-)Einrichtung reagieren, zumindest also (im Installationsmodus) gezielt Anweisung geben, was zu ändern ist.

                          Am Ende hat der Client seinen Browser verkonfiguriert, dann bist du mit deinem Versuch auch machtlos.

                          echo "$verabschiedung $name";

                        2. Moin!

                          »» Entscheide dich für einen Zeichensatz - und bleib dabei.

                          Das ist das Problem. Es ist nicht meine Entscheidung, was ein Verwender nachher im Einsatz hat.

                          Der Verwender wird nicht in deinen PHP-Skripten herumfummeln, jedenfalls sollte er das nicht tun, oder er sollte wissen, was er tut.

                          Die meisten Scripte müssen sowohl auf Servern laufen, die ISO-8859-1 nutzen, als auch auf solchen, die UTF-8 benutzten.

                          Kein Server nutzt von sich aus das eine oder andere, ohne dass es sich ändern lässt. Genauer gesagt nutzt ein Server eigentlich gar keine Codierung, sondern liefert nur Bytes aus - und wie die im HTTP-Header getaggt sind, ist im Zweifel der PHP-Applikation überlassen, die entsprechende Header auch manuell programmiert setzen kann, um sicherzugehen, dass kein Default-Encoding dazwischenfunkt.

                          Man kann also in der Regel problemlos eine UTF-8-Applikation bauen, ohne sich um Server-Probleme kümmern zu müssen, wenn man sich an allen Schnittstellen mit externen Kommunikationspartnern (Browser, Datenbank, Mail) darum kümmert, korrekte Encoding-Angaben mitzuliefern.

                          Ich möchte die Scripte daher so absichern, dass sie sich entweder weigern, falsch eingerichet zu arbeiten oder eben besser, nach Möglichkiet auf die (Fehl-)Einrichtung reagieren, zumindest also (im Installationsmodus) gezielt Anweisung geben, was zu ändern ist.

                          Dein Test auf die Stringlänge von Umlauten wird immer korrekt den Zustand widergeben, der zum Zeitpunkt des Speicherns dieses Skriptes vorherrschte. Wenn du das Skript als UTF-8 speicherst, werden 6 Bytes in die Datei geschrieben, von PHP auf jedem Server der Welt auch als 6 Bytes wieder erkannt, und deshalb ist strlen() dann immer 6.

                          Daran ändert sich auch nichts, wenn ein unbedarfter PHP-Programmierer die Datei in einem ISO-8859-1-Editor öffnet, und irgendwo anders falsche Umlaute einfügt. Denn der String ganz oben wird dann ja als 6 "unleserliche" ISO-Zeichen angezeigt und wieder abgespeichert - und der Check auf strlen() ändert sich gar nicht.

                          Erst wenn der Bearbeiter die Datei tatsächlich umcodiert, würde der Check in die andere Fallunterscheidung laufen. Aber wer wird sowas idiotisches tun, ohne sich selbst für die Konsequenzen verantwortlich zu machen?

                          - Sven Rautenberg

                          1. Hello,

                            Daran ändert sich auch nichts, wenn ein unbedarfter PHP-Programmierer die Datei in einem ISO-8859-1-Editor öffnet, und irgendwo anders falsche Umlaute einfügt. Denn der String ganz oben wird dann ja als 6 "unleserliche" ISO-Zeichen angezeigt und wieder abgespeichert - und der Check auf strlen() ändert sich gar nicht.

                            Erst wenn der Bearbeiter die Datei tatsächlich umcodiert, würde der Check in die andere Fallunterscheidung laufen. Aber wer wird sowas idiotisches tun, ohne sich selbst für die Konsequenzen verantwortlich zu machen?

                            Ich befürchte, dass ich Dir da zustimmen muss. Und Du weißt ja, dass mir das sehr schwer fällt :-P

                            Da ist es tatsächlich einfacher, dem Server einen passenden Header zu verpassen und zu hoffen, dass der dann auch gültig bleibt.

                            Bleibt also noch der Fall:
                            Jemand übernimmt eine Funktionssammlung oder eine Klasse und erweitert sie in der falschen Codierung.
                            Dann gibt es Zeichenmüsli bei allen Ausgaben...

                            Der Code sollte ja nicht davon betroffen sein, wenn sich brav an ASCII gehalten hat, also auch bei Arrays keine Elementnamen mit Zeichencodes über 127d genommen hat... ?

                            Liebe Grüße aus dem schönen Oberharz

                            Tom vom Berg

                            --
                            Nur selber lernen macht schlau
                            http://bergpost.annerschbarrich.de
                            1. Moin!

                              Bleibt also noch der Fall:
                              Jemand übernimmt eine Funktionssammlung oder eine Klasse und erweitert sie in der falschen Codierung.
                              Dann gibt es Zeichenmüsli bei allen Ausgaben...

                              Das ist dann eben das Schicksal. Wer programmiert, muss sich Gedanken ums Encoding machen. Genauso wie ums Escaping, etc...

                              Der Code sollte ja nicht davon betroffen sein, wenn sich brav an ASCII gehalten hat, also auch bei Arrays keine Elementnamen mit Zeichencodes über 127d genommen hat... ?

                              PHP hat keine Probleme mit Bezeichnern, in denen "Sonderzeichen" enthalten sind. Die Probleme gibts nur, wenn die Sonderzeichen durch mangelhafte Editor-Bedienung in verschiedenen Codierungen auftauchen.

                              - Sven Rautenberg

                              1. Hello,

                                Der Code sollte ja nicht davon betroffen sein, wenn sich brav an ASCII gehalten hat, also auch bei Arrays keine Elementnamen mit Zeichencodes über 127d genommen hat... ?

                                PHP hat keine Probleme mit Bezeichnern, in denen "Sonderzeichen" enthalten sind. Die Probleme gibts nur, wenn die Sonderzeichen durch mangelhafte Editor-Bedienung in verschiedenen Codierungen auftauchen.

                                Genau darum geht es.
                                Es sind schon diverse Funktionssammlungen aus den letzten Jahren im Umlauf, die alle in ISO-8859-1 erfasst worden sind. Die müssen dann alle ausgetauscht werden gegen Versionen, die in UTF-8 abgespeichert wurden, wenn jetzt neue in UTF-8 dazukommen. Der sichtbare Code auf dem Bildschirm ist ja beides Mal derselbe bei richtiger Browsereinstellung. Nur das Bitabbild in der Datei unterscheidet sich.

                                Wenn da nun eine installierte Funktionssammlung in ISO mit einer neuen in UTF-8 zusammenarbeiten soll, und es gibt Umlaute in Arraybezeichnern, passen die beiden nicht mehr zusammen.

                                Bezogen auf den Beispiel-Fall uas diesem Thread (Erzeugung von Schlüsselwerten), muss außerdem noch Rücksicht genommen werden darauf, wo denn diese Schlüssel nachher zum Einsatz kommen sollen - in einer ASCII-Textdatei, in einer Datenbank oder sonstwo. Das Problem steckt nicht darin, etwas ganz und gar neu aufzubauen, sondern vorhandene Projekte umszustellen und dann zu erweitern/zu ändern.

                                Ich bin mir da noch nicht im Klaren darüber, an was man da alles denken muss.

                                • Codierung des Scriptes

                                • Eigene Datenbank

                                • Fremde Datenbankzugänge

                                • Zusammenarbeit mit anderen Seiten

                                • Dateisysteme

                                • Ausgabe des Webservers

                                • Request beim Webserver

                                • ???

                                Liebe Grüße aus dem schönen Oberharz

                                Tom vom Berg

                                --
                                Nur selber lernen macht schlau
                                http://bergpost.annerschbarrich.de
                  2. echo $begrüßung;

                    In Formularen kann man den das erwartete Encoding spezifizieren (accept-charset).

                    Versprich dir nicht zu viel davon. Es gab da mal irgendwo einen Test, der ergab, dass dieses Attribut ziemlich oft ignoriert wird. Am wahrscheinlichsten ist immer noch, dass der Browser die Formulardaten in der Kodierung des das Formular enthalten Dokuments versendet.

                    echo "$verabschiedung $name";

                    1. Moin!

                      »» In Formularen kann man den das erwartete Encoding spezifizieren (accept-charset).

                      Versprich dir nicht zu viel davon. Es gab da mal irgendwo einen Test, der ergab, dass dieses Attribut ziemlich oft ignoriert wird. Am wahrscheinlichsten ist immer noch, dass der Browser die Formulardaten in der Kodierung des das Formular enthalten Dokuments versendet.

                      Jein - das Attribut wird beachtet, macht aber aus den Formulardaten in der Regel Datenmüll, den man serverseitig nicht mehr ordentlich auseinanderfummeln kann.

                      Die Sache ist eigentlich recht einfach: Wenn die Seite in ISO-8859-1 ist, ist es erwartungskonform, wenn das Formular auch ISO-8859-1 zurücksendet, weil die Applikation damit offenbar umgehen kann - und alle anderen Zeichen außerhalb dieser Codierung werden dann eben unbrauchbar (was sich je nach Browser unterschiedlich äußern kann).

                      Ist die Seite in UTF-8, darf das Formular UTF-8 zurücksenden, weil die Applikation damit offenbar umgehen kann. Bonus dieses Falls ist, dass alle eingebbaren Zeichen codiert werden können, und somit keine Verluste eintreten.

                      Deshalb: Immer UTF-8 verwenden, damit hat man am wenigsten Probleme.

                      - Sven Rautenberg

          3. Hello,

            auf einem Debian 4.0 mit PHP 5.2.6-5 (neuestes aus den Packages)

            randomString() took 1.06002783775 seconds and generated 10000 unique strings in 10000 runs
            get_random_str() took 0.866553068161 seconds and generated 10000 unique strings in 10000 runs

            Könnte also mit array_rand() auf der Windows-Version von PHP zu tun haben?

            Liebe Grüße aus dem schönen Oberharz

            Tom vom Berg

            --
            Nur selber lernen macht schlau
            http://bergpost.annerschbarrich.de
        2. Hello,

          für den Laufzeittest ist es übrigens relevant, welche der beiden Funktionen man zuerst laufen lässt, wenn man sie in einem gemeinsamen Script benutzt.

          Das wird an der dynamischen Speicherallokation liegen.

          Vermutlich liegt es daran, dass der dem Script initial zugewiesene Speicher schneller allokiert werden kann für die zusätzlichen Arrayelemente, als wenn auch immer noch Speicher vom OS angefordert werden muss, weil der dem Script typisch zugewiesene Speicherblock bereits verbraucht ist.

          Liebe Grüße aus dem schönen Oberharz

          Tom vom Berg

          --
          Nur selber lernen macht schlau
          http://bergpost.annerschbarrich.de
  2. Hi,

    in eine Tabelle mit einigen tausend Adressen möchte ich jeder Adresse einen eindeutigen Zugriffscode zuordnen.

    Der wo zur Anwendung kommen soll?
    Soll ihn sich bspw. ein Benuzter *dauerhaft* merken können müssen - oder wird er einmalig als Link-Parameter verwendet o.ä.?

    Das Datenfeld ist UNIQUE und soll eine Zufallskombination von 8 Zahlen und Buchstaben erhalten, die man nicht "erraten" kann.

    Ich könnte Zufallszahlen generieren, die mit md5 umwandeln. Aber dann habe ich 16 Zeichen. Ist es sinnvoll, daraus 8 zu entnehmen?

    Nein, eigentlich nicht.
    Die "Eindeutigkeit" kann eine solche Hashfunktion nur über die komplette Ergebnislänge garantieren.
    Wenn du daraus Teile entnimmst, steigt die Wahrscheinlichkeit für Kollisionen stark an.

    Und selber basteln, auf Basis von Ausgangswerten wie aktueller Zeit in Millisekunden etc., sollte man sowas schon mal gar nicht - da kann man sehr schnell etwas zusammenstöpseln, was sehr leicht angreifbar ist.

    PHP bietet dir bspw. uniqid() (minimale Länge 13 Characters), und MySQL UUID() - und ab Version 5.1.20 auch UUID_SHORT(), was im Gegensatz zu den 128 des vorgenannten einen "nur" 64 Bit langen Wert liefert.

    MfG ChrisB

    --
    Light travels faster than sound - that's why most people appear bright until you hear them speak.
    1. Hello,

      Und selber basteln, auf Basis von Ausgangswerten wie aktueller Zeit in Millisekunden etc., sollte man sowas schon mal gar nicht - da kann man sehr schnell etwas zusammenstöpseln, was sehr leicht angreifbar ist.

      Da mache ich mir bei mt_rand() eigentlich keine großen Sorgen mehr.
      Und ein Array mit 5000 Unique-Schlüsseln ist damit in Nullkommanix erstellt.

      Liebe Grüße aus dem schönen Oberharz

      Tom vom Berg

      --
      Nur selber lernen macht schlau
      http://bergpost.annerschbarrich.de
      1. Hallo Tom.

        » Und selber basteln, auf Basis von Ausgangswerten wie aktueller Zeit in Millisekunden etc., sollte man sowas schon mal gar nicht - da kann man sehr schnell etwas zusammenstöpseln, was sehr leicht angreifbar ist.
        Da mache ich mir bei mt_rand() eigentlich keine großen Sorgen mehr.

        Solltest du aber :-)

        Servus,
        Flo

        1. Hello,

          » Und selber basteln, auf Basis von Ausgangswerten wie aktueller Zeit in Millisekunden etc., sollte man sowas schon mal gar nicht - da kann man sehr schnell etwas zusammenstöpseln, was sehr leicht angreifbar ist.
          Da mache ich mir bei mt_rand() eigentlich keine großen Sorgen mehr.

          Solltest du aber :-)

          Danke für den Link.
          Bei PHP >= 5.2.6 sollten diese Probleme aber behoben sein.

          Da gab es aber noch irgend eine andere Geschichte, wo ein wilder Zugriff auf den Speicher von Lektoren beseitigt wurde, und gegen einen "ordentlichen Zugriff" (Initialisierung) ausgetauscht wurde, was dann zu einer Lücke führte.

          Aber das war, glaube ich, bei SSL, oder?

          jedenfalls hatte es wohl mit ungenügender Dokumentation zu tun.

          Liebe Grüße aus dem schönen Oberharz

          Tom vom Berg

          --
          Nur selber lernen macht schlau
          http://bergpost.annerschbarrich.de
    2. Der wo zur Anwendung kommen soll?

      Kunden sollen die Möglichkeit haben, ihre eigenen Daten einzusehen. Aber durch Eingabe anderer Code eben nicht andere Daten.

      Die ID des Kunden (z.Z. als UNIQUE Schlüssel verwendet) verbietet sich also.

      Ein Einloggen mit der ID wird abgewiesen. Aber das "manuelle" Erfinden sicherer Zugangscodes ist bei zweitausend Kunden nicht machbar.