Zufallstext

Dieser Bereich dient dazu, neue Features zu diskutieren und für die Entwicklung zu dokumentieren. // This area is dedicated to new features including proposals and documentation.
Benutzeravatar
dave
Beiträge: 903
Registriert: 04.02.2011, 19:03:57
Wohnort: Berlin
Kontaktdaten:

Zufallstext

Beitrag von dave » 06.03.2011, 14:44:12

Hallo,

bin heute auf das Problem gestossen, dass ich gerne einen zufälligen String generiert hätte. Dazu gibts ja auch unzählige Funktionen, ist also kein Problem.

Wäre es sinnvoll, eine kleines Tool oder eine Extension mit diversen Einstellmöglichkeiten zu schreiben? Würde sowas Anklang finden, wäre das eine kleine Bereicherung fürs APF?

Benutzeravatar
Screeze
Beiträge: 1920
Registriert: 05.08.2009, 09:49:04
Kontaktdaten:

Re: Zufallstext

Beitrag von Screeze » 06.03.2011, 14:53:39

Hm mir fällt kein Anwendungsfall ein einen zufallstext zu bekommen.
Davon abgesehen sind das ein paar zeilen code nur, je nach quelle der texte....

Benutzeravatar
dr.e.
Administrator
Beiträge: 4533
Registriert: 04.11.2007, 16:13:53

Re: Zufallstext

Beitrag von dr.e. » 06.03.2011, 14:54:28

Hallo dave,

immer gerne. Aktuell gibt es den stringAssistant, der allerdings deinen Anwendungsfall nur in Form des CAPTCHA-Strings beherrscht. Diese könnte man aber dahingehend ausbauen, dass der CAPTCHA-String nur ein Anwendungsfall einer weitaus generischeren Möglichkeit ist. Zudem könnte man die Klasse mal mit einem Großbuchstaben am Anfang ausstatten (das kann auch gerne ich übernehmen).

Wenn du möchtest, bringe den Code mal dahin und wir diskutieren kurz über den Einbau.
Viele Grüße,
Christian

Benutzeravatar
dave
Beiträge: 903
Registriert: 04.02.2011, 19:03:57
Wohnort: Berlin
Kontaktdaten:

Re: Zufallstext

Beitrag von dave » 07.03.2011, 22:05:30

Guten Abend :)
Ich habe da mal was vorbereitet ...
:lol:

Hier mal meine Klasse RandomStringManager:

Code: Alles auswählen

    import('core::database', 'MySQLxHandler');

    class RandomStringManager extends APFObject {
    
        private $chars;
        private $lenght;
        private $randomString;
    
        public function __construct($chars = '', $lenght = '') {
            if($chars === '') {
                $this->chars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
            }else{
                $this->chars = $chars;
            }
            if(empty($lenght)) {
                $this->lenght = 16;
            }else{
                $this->lenght = $lenght;
            }
            
            $this->randomString = '';
        }
        

        
        public function createHash() {
            for($i = 0; $i < $this->lenght; $i++) {
                $this->randomString .= $this->chars[mt_rand(0, strlen($this->chars) - 1)];
            }
            
            return $this->randomString;
        }


    
        public function advancedCreateHash($select) {
            $this->randomString = '';
            
            if($select === '') {
                throw new Exception('You must provide a SQL query!',E_USER_ERROR);
            }
            
            $cM = &$this->__getServiceObject('core::database','ConnectionManager');
            $cM->setContext('projectone');
            $SQL = &$cM->getConnection('database-1');

            $code         = $this->createHash();
            $selection    = $select." = '$code'";
            $result     = $SQL->executeTextStatement($selection);        
            
            while($SQL->getNumRows($result) > 0) {
                $this->advancedCreateHash($select);
                break;
            }
            
            return $this->randomString;            
        }
        
    }
 
Die Klasse stellt 2 Methoden zu Verfügung:
  • einfaches Erstellen eines zufälligen String
  • erstellen eines zufälligen String mit Abfrage, ob dieser in der DB bereits existiert - sollte dies der Fall sein, wird ein neuer zufälliger String generiert
Folgende Aufrufe sind möglich:

Code: Alles auswählen

    $randomString = new RandomStringManager('', 10);        
    echo $randomString->createHash();
 
Erklärung:
Keine bestimmten Zeichen für den String vorgeben -> Standard nutzen; Länge des String: 10 Zeichen
So könnte eine Ausgabe aussehen: kjh23UbnxB

Code: Alles auswählen

    $randomString = new RandomStringManager('0123456789abcdef', '');         
    echo $randomString->advancedCreateHash('SELECT Activationcode FROM ent_activation WHERE Activationcode');
 
Erklärung:
Nur diese Zeichenfolge (0123456789abcdef) verwenden; keine vorgegebene Länge -> Standard = 16 Zeichen
Ausgabe mit Abgleich der DB, sollte ein generierter String existieren, wird solange ein neuer eneriert, bis dieser nicht existiert


Bei zweiter Methode gibt es mit Sicherheit noch Verbesserungsvorschläge, gerade was die Übergabe des Select angeht. Da wusste ich mir aber einfach erstmal nicht besser zu helfen ;). Und den Context musste ich manuell setzen, der kommt nicht vom APFObject? Das habe ich bisher auch nocht nicht verstanden :D
Über Anregungen, Kritik und Hinweise freue ich mich sehr. Bei mir ist das übrigens im Ordner Tools erstmal gelandet ^^.

Benutzeravatar
dr.e.
Administrator
Beiträge: 4533
Registriert: 04.11.2007, 16:13:53

Re: Zufallstext

Beitrag von dr.e. » 12.03.2011, 11:53:01

Hi dave,

ich hab' dich nicht vergessen, der Post war bei mir nur noch auf der TODO-Liste offen. :) Hier meine Anmerkungen:
  • Das import() am Anfang kannst du dir schenken, das wird durch den ConnectionManager schon abgebildet.
  • Der Context wird deshalb nicht durchgereicht, weil du den RandomStringManager nicht mit dem ServiceManager - sprich mit getServiceObject()/getAndInitServiceObject()/getDIServiceObject() erzeugst. Das sollte im Code entsprechend vorgesehen werden, sonst ist die Komponente nicht generisch einsetzbar.
  • Den zweiten Anwendungsfall verstehe ich nicht so ganz. Welchen Sinn macht es, eine Datenbank zu prüfen, ob eine Zufallszahl schon erzeugt wurde?
Viele Grüße,
Christian

Benutzeravatar
dave
Beiträge: 903
Registriert: 04.02.2011, 19:03:57
Wohnort: Berlin
Kontaktdaten:

Re: Zufallstext

Beitrag von dave » 12.03.2011, 13:01:12

Ich schaue mir das heute Nachmittag/Abend nochmal etwas genauer an. Danke soweit.
dr.e. hat geschrieben:Den zweiten Anwendungsfall verstehe ich nicht so ganz. Welchen Sinn macht es, eine Datenbank zu prüfen, ob eine Zufallszahl schon erzeugt wurde?
Dafür habe ich folgenden Anwendungsfall: Es können Bilder hochgeladen werden. Diese Bilder nenne ich dann nach einem Zufallsmuster um und speichere den String in der DB. Jedoch ist es trotz Zufall immer noch möglich, dass der String doppelt generiert wird. Das wäre Schade und das Bild somit futsch. Dazu dient die Abfrage, ob der String schon vorhanden ist ;).
Ein anderer Fall wäre ein Aktivierungskey, der kurz (kein ewig langer md5()-Hash) und einmalig sein soll ;)

Ich bin mir aber noch nicht so ganz sicher, ob man bei der Datenbankgeschichte nicht besser mit dem GORM arbeitet ... mal guggen, bin ja noch beim experimentieren :)

Benutzeravatar
dr.e.
Administrator
Beiträge: 4533
Registriert: 04.11.2007, 16:13:53

Re: Zufallstext

Beitrag von dr.e. » 12.03.2011, 18:10:11

Hi dave,

den zweiten Anwendungsfall bilde ich in meinen CMS-Komponenten so ab, dass ich den Bild-Namen sanitize und einen eindeutigen Zeitstempel anhänge. Das ist performanter und genauso sicher.

Hier der Code:

Code: Alles auswählen

final class FileNameSanitizer {

   public static function sanitize($name) {

      // sanitize name
      $cleanFileName = self::clean($name);

      // make unique
      $dot = strrpos($cleanFileName, '.');
      $ext = substr($cleanFileName, $dot + 1);
      $body = substr($cleanFileName, 0, $dot);

      // limit body length
      $body = substr($body, 0, 40);

      return $body . '_' . time() . '.' . $ext;
   }

   public static function clean($name) {
      return preg_replace('/[^A-Za-z0-9-_.]/i', '', strtolower($name));
   }

} 
Viele Grüße,
Christian

Benutzeravatar
dave
Beiträge: 903
Registriert: 04.02.2011, 19:03:57
Wohnort: Berlin
Kontaktdaten:

Re: Zufallstext

Beitrag von dave » 12.03.2011, 19:06:11

Wie sieht in deinem Fall der Name des Bildes dann aus?

Ich hätte gerne einen Namen, auf den man nicht so einfach schliessen kann, den man nicht einfach in der URL ändern kann und ein anderes Bild sieht ;).

Und das mit dem Bild ist nur ein Beispiel, der kurze Aktivierungscode ist ja auch ganz interessant.

Benutzeravatar
dave
Beiträge: 903
Registriert: 04.02.2011, 19:03:57
Wohnort: Berlin
Kontaktdaten:

Re: Zufallstext

Beitrag von dave » 12.03.2011, 22:44:02

Ich habe mir das jetzt nochmal angesehen und "umgebaut":
dr.e. hat geschrieben:Der Context wird deshalb nicht durchgereicht, weil du den RandomStringManager nicht mit dem ServiceManager - sprich mit getServiceObject()/getAndInitServiceObject()/getDIServiceObject() erzeugst. Das sollte im Code entsprechend vorgesehen werden, sonst ist die Komponente nicht generisch einsetzbar.
Jo, ich habe das jetzt soweit umgemodelt, dass das nun klappt und der Context automatisch gesetzt wird :). Über das getServiceObject() wird also auch der Context mit übergeben. Gut zu wissen. Also am besten alle Erweiterungen so einbinden. Alles klar!

Ein Problem habe ich nun allerdings: Es werden immer nur die Standard-Konfiguration verwendet. Also 16 Zeichen länge und 1-9a-zA-Z. Wie kann ich der Klasse eigene Parameter übergeben?
Ich habe bereits getAndInitServiceObject() mit einem 3. Parameter-Satz probiert, habe aber kein Ergebnis erzielen können.

Ich poste übrigens nochmal meinen angepassten RondomStringManager :D

Code: Alles auswählen

<?php

    class RandomStringManager extends APFObject {
    
        private $chars;
        private $lenght;
        private $randomString;
    
        public function __construct($chars = '', $lenght = '') {
            if($chars === '') {
                $this->chars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
            }else{
                $this->chars = $chars;
            }
            if(empty($lenght)) {
                $this->lenght = 16;
            }else{
                $this->lenght = $lenght;
            }
            
            $this->randomString = '';
        }
        

        
        public function createHash() {
            for($i = 0; $i < $this->lenght; $i++) {
                $this->randomString .= $this->chars[mt_rand(0, strlen($this->chars) - 1)];
            }
            
            return $this->randomString;
        }


    
        public function advancedCreateHash($select) {
            $this->randomString = '';
            
            if($select === '') {
                throw new Exception('You must provide a SQL query!',E_USER_ERROR);
            }
            
            $cM = &$this->__getServiceObject('core::database','ConnectionManager');
            $SQL = &$cM->getConnection('database-1');

            $code         = $this->createHash();
            $selection    = $select." = '$code'";
            $result     = $SQL->executeTextStatement($selection);        
            
            while($SQL->getNumRows($result) > 0) {
                $this->advancedCreateHash($select);
                break;
            }
            
            return $this->randomString;            
        }
        
    }
?>

Benutzeravatar
dr.e.
Administrator
Beiträge: 4533
Registriert: 04.11.2007, 16:13:53

Re: Zufallstext

Beitrag von dr.e. » 12.03.2011, 22:48:01

Hi dave,
Ein Problem habe ich nun allerdings: Es werden immer nur die Standard-Konfiguration verwendet. Also 16 Zeichen länge und 1-9a-zA-Z. Wie kann ich der Klasse eigene Parameter übergeben?
Ich habe bereits getAndInitServiceObject() mit einem 3. Parameter-Satz probiert, habe aber kein Ergebnis erzielen können.
Das "Geheimnis" ist die zu implementierende init()-Methode (siehe http://adventure-php-framework.org/Seit ... e-Services). Diese Methode erhält das, was du in der getAndInitServiceObject() als dritten Parameter übergibst. Dort kannst du dann deine Klasse initialisieren.
Viele Grüße,
Christian

Benutzeravatar
dave
Beiträge: 903
Registriert: 04.02.2011, 19:03:57
Wohnort: Berlin
Kontaktdaten:

Re: Zufallstext

Beitrag von dave » 12.03.2011, 22:50:27

Ah, vielen Dank! Manches ist aus der Doku "schwer" heraus zu lesen, gerade wenn man schon seit 4 Uhr auf den Beinen ist ;). Schau ich mir Morgen sofort in Ruhe an.

Benutzeravatar
dave
Beiträge: 903
Registriert: 04.02.2011, 19:03:57
Wohnort: Berlin
Kontaktdaten:

Re: Zufallstext

Beitrag von dave » 13.03.2011, 21:44:40

HiHo und schönen guten Abend,

Ich habe mein Tool RandomStringManager nun nochmal etwas aufpoliert:

Code: Alles auswählen

<?php

class RandomStringManager extends APFObject {

    private $chars;
    private $lenght;
    private $randomString;

    public function __construct() {
        $this->randomString = '';
    }

    public function init($initParam) {
        if ($initParam['chars'] === '') {
            $this->chars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        } else {
            $this->chars = $initParam['chars'];
        }
        if (empty($initParam['lenght'])) {
            $this->lenght = 16;
        } else {
            $this->lenght = $initParam['lenght'];
        }
    }

    public function createHash() {
        for ($i = 0; $i < $this->lenght; $i++) {
            $this->randomString .= $this->chars[mt_rand(0, strlen($this->chars) - 1)];
        }

        return $this->randomString;
    }

    public function advancedCreateHash($select, $connectionKey) {
        $this->randomString = '';

        if ($select == '') {
            throw new Exception('[RandomStringManager::advancedCreateHash()] You must provide a SQL query!', E_USER_ERROR);
        }

        if($connectionKey == '') {
            throw new Exception('[RandomStringManager::advancedCreateHash()] You must provide a ConnectionKey for the SQL Statement!', E_USER_ERROR);
        }

        $cM = &$this->__getServiceObject('core::database', 'ConnectionManager');
        $SQL = &$cM->getConnection($connectionKey);

        $code = $this->createHash();
        $selection = $select . "'$code'";
        $result = $SQL->executeTextStatement($selection);

        while ($SQL->getNumRows($result) > 0) {
            $this->advancedCreateHash($select, $connectionKey);
            break;
        }

        return $this->randomString;
    }

}

?>

Zur Verwendung:

Initialisierung und Übergabe der zulässigen Zeichen und der Länge des String:

Code: Alles auswählen

$randomString = &$this->__getAndInitServiceObject('tools::randomstring', 'RandomStringManager', array('chars' => '', 'lenght' => 10)); 
-> folgende Zeichen werden verwendet: 1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ, Länge: 10 Zeichen
-> mögliche Ausgabe: QxC1RCAqFX

Einfachen, zufälligen String generieren und ausgeben:

Code: Alles auswählen

$Aktivierungscode = $randomString->createHash();
echo $Aktivierungscode; 


Zufälligen String erzeugen und überprüfen, ob dieser bereits in der DB mit dem ConnectionKey 'database-1' existiert:

Code: Alles auswählen

$Aktivierungscode = $randomString->advancedCreateHash('SELECT Activationcode FROM ent_activation WHERE Activationcode =', 'database-1');
echo $Aktivierungscode; 
-> Es wird die Spalte 'Activationcode' in der Tabelle 'ent_activation' über ein Vorkommen des generierten String durchsucht. Sollte dies der Fall sein, wird ein neuer String erzeugt, bis dieser nicht mehr existiert.
-> mögliche Ausgabe: QxC1RCAqFX
Hinweis: An das SQL-Statement wird in der RandomStringManager-Klasse ein

Code: Alles auswählen

"'$code'" 
angehängt.

Was bisher fehlt: Man kann auch eine Länge des gewünschten String von 'qwertz' vorgeben, was jedoch zu einem fatalen Fehler führen würde. Hier könnte evtl. noch ein check auf is_int eingebaut werden ;).


Feedback jederzeit Willkommen :)

Benutzeravatar
Screeze
Beiträge: 1920
Registriert: 05.08.2009, 09:49:04
Kontaktdaten:

Re: Zufallstext

Beitrag von Screeze » 13.03.2011, 22:35:19

Ich würde hier drin auf jedenfall eine SQL-injection abfangen, das "'$code'" einfach dranhängen ist böse....

Benutzeravatar
dave
Beiträge: 903
Registriert: 04.02.2011, 19:03:57
Wohnort: Berlin
Kontaktdaten:

Re: Zufallstext

Beitrag von dave » 13.03.2011, 22:36:52

Guter Hinweis! Habe es bearbeitet: und die Var mal in $hash umbenannt ;)

Code: Alles auswählen

<?php

class RandomStringManager extends APFObject {

    private $chars;
    private $lenght;
    private $randomString;

    public function __construct() {
        $this->randomString = '';
    }

    public function init($initParam) {
        if ($initParam['chars'] === '') {
            $this->chars = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        } else {
            $this->chars = $initParam['chars'];
        }
        if (empty($initParam['lenght'])) {
            $this->lenght = 16;
        } else {
            $this->lenght = $initParam['lenght'];
        }
    }

    public function createHash() {
        for ($i = 0; $i < $this->lenght; $i++) {
            $this->randomString .= $this->chars[mt_rand(0, strlen($this->chars) - 1)];
        }

        return $this->randomString;
    }

    public function advancedCreateHash($select, $connectionKey) {
        $this->randomString = '';

        if ($select == '') {
            throw new Exception('[RandomStringManager::advancedCreateHash()] You must provide a SQL query!', E_USER_ERROR);
        }

        if($connectionKey == '') {
            throw new Exception('[RandomStringManager::advancedCreateHash()] You must provide a ConnectionKey for the SQL Statement!', E_USER_ERROR);
        }

        $cM = &$this->__getServiceObject('core::database', 'ConnectionManager');
        $SQL = &$cM->getConnection($connectionKey);

        $hash = $this->createHash();
        $hash = $SQL->escapeValue($hash);
        $selection = $select . "'$hash'";
        $result = $SQL->executeTextStatement($selection);

        while ($SQL->getNumRows($result) > 0) {
            $this->advancedCreateHash($select, $connectionKey);
            break;
        }

        return $this->randomString;
    }

}

?>
Muss das morgen aber nochmal testen. Ich bin mir noch nicht ganz sicher, wie sich das nun mit Sonderzeichen in meinem gewünschten String verhält ... Übrigens: Netbeans ist toll ;)

Benutzeravatar
dave
Beiträge: 903
Registriert: 04.02.2011, 19:03:57
Wohnort: Berlin
Kontaktdaten:

Re: Zufallstext

Beitrag von dave » 14.03.2011, 19:09:19

Ich bin das nun nochmal intensiv mit dem escapeValue(); durchgegangen. Konnte soweit keine Probleme feststellen. Einzig das Zeichen § (Paragraphenzeichen) machte Probleme und es wurde ein Fragezeichen ausgegeben. Habe aber auch keine Möglichkeit gefunden, das zu korrigieren. Ansonsten läuft das ganz gut und bin damit sehr zufrieden :D (Eigenlob stinkt ^^)

Gesperrt

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast