Hallo vapita,
hash() - ok 😀
verify() - ok 😀
Den Grund, warum deine Methoden Arrays verarbeiten sollen, habe ich jetzt endlich verstanden 🤦♂️. Aber warum sie auch Strings können sollen, hm. Password::verify
hat einen auf array
getypten Parameter, da können die privaten Methoden nichts anderes bekommen. Du kannst in diesen privaten Helfern davon ausgehen, dass ein Array herein kommt und sie ebenfalls auf array
typen.
isString() - vom Algorithmus her nach wie vor nicht ok. Wenn Du in der Schleife einfach nur an $passwordIsString zuweist, ist das Ergebnis immer das vom letzten Schleifendurchlauf. Es gibt zwei richtige Techniken: (1) verwende eine UND Verknüpfung, (2) weise nur zu, wenn die Prüfung FALSE ergibt.
Und der ?? Operator in der Schleife ist nach wie vor unnötig, is_string gibt niemals NULL zurück.
Also, entweder (vom Prinzip her) so:
$passwordIsString = true;
foreach ($array as $item) {
if (!is_string($item))
$passwordIsString = false;
}
oder so
$passwordIsString = true;
foreach ($array as $item) {
$passwordIsString = $passwordIsString && is_string($item);
}
Man muss das im zweiten Beispiel leider so umständlich schreiben. PHP kennt zwar kombinierte Zuweisungen bei Arithmetik (+=
, -=
etc), aber kein &&=
.
Wenn nach der Schleife - so wie bei Dir - nichts mehr passiert, kannst Du es auch vereinfachen, wobei die Päpste strukturierter Programmierung darüber die Stirn runzeln dürften. Ich nicht, ich mache sowas gern.
foreach ($array as $item) {
if (!is_string($item)) return false;
}
return true;
Mit funktionalen Ansätzen wie array_reduce
und Pfeilfunktionen (ab PHP 7.4) komme ich Dir jetzt besser nicht 🙊
isEqual() - nicht prinzipiell falsch, aber hier ist nochmal das Konzept gefragt. Wenn isString ein beliebig langes Array verarbeiten kann, sollte das isEqual dann nicht auch tun? Die Methoden einer Klasse sollten eine logische Konsistenz aufweisen. Wenn Du beliebig viele PW verarbeiten können willst:
function isEqual(array $password) {
if (count($password) < 2) return true;
$comp = $password[0];
foreach ($password as $pw)
if ($pw !== $comp) return false;
return true;
}
Diese Methode ist zwar leicht ineffizient, weil sie den ersten Eintrag des Arrays mit sich selbst vergleicht, aber andernfalls könntest Du nicht foreach benutzen, es müsste eine for ($i=1; $i<count($password); $i++)
Schleife sein. Das ist auch nicht besser.
isComplex - ich finde die Anforderungen zu strikt. Normal ist es, drei von vier dieser Kategorien zu verlangen. Alle vier ist sehr streng, und vor allem ist der Zwang zu @#-_$%^&+=§!? zu streng. Ich möchte das Passwort "Lämmlein*17" verwenden! Vermutlich kann man meine folgenden Überlegungen heiß diskutieren; es ist nur meine eigene Meinung aus 36 Berufsjahren, die ich als Opfer der IT-Security verbracht habe, nicht als Täter.
Auf Internationalisierungsprobleme will ich gar nicht erst eingehen (was macht ein Russe, der kyrillisch tippt? Was macht ein Chinese mit seinen Ideogrammen?). Um hier besser zu werden, müsste man mittels Unicode-Kategorie prüfen. \p{Lu} sind Großbuchstaben, \p{Ll} Kleinbuchstaben und \p{Nd} Ziffern. Und dann noch ein Zeichen, was in diesen Kategorien nicht ist. Dafür muss man, denke ich, vier mal matchen, und man darf nicht preg_match nehmen, sondern es muss mb_ereg
sein (diese Funktion ist Unicode-fähig und kann mit UTF-8 codierten Strings umgehen). Nicht mb_ereg_match
, die verankert die Prüfung am Beginn. Wir wollen aber nur die Existenz eines Zeichens testen.
function isComplex($password) {
$password = (is_array($password)) ? array_pop($password) : $password;
$spaceCount = mb_strlen($p) - mb_strlen(mb_ereg_replace("\p{Zs}", "", $p));
$hasUpper = mb_ereg("\p{Lu}", $p);
$hasLower = mb_ereg("\p{Ll}", $p);
$hasOther = mb_ereg("\p{Lo}", $p);
$hasNumber = mb_ereg("\p{Nd}", $p);
$hasOther = mb_ereg("(?!(\p{Nd}|\p{Ll}|\p{Lu}|\p{Zs})).", $p);
}
Und jetzt braucht man eine Entscheidungsregeln. Ich würde beispielsweise ein Passwort akzeptieren, dass nur (kleinbuchstaben oder großbuchstaben) und space enthält, aber länger als 25 Zeichen ist (siehe "correct horse battery staple"). Der Space-Anteil sollte aber unter - sagenwirmal - 15% liegen (das korrekte Pferd hat schon 10,7%!). Die $hasOther Kategorie trifft viele Fremdalphabete, z.B. finde ich bei Thai oder Arabisch nur \p{Lo } Zeichen. Diese 字亦属.
Diese Regeln solltest Du jetzt für Dich formulieren, und dann der Reihe nach prüfen, ob sie erfüllt sind.
Oder Du bleibst bei deiner Regex, wenn Dir das jetzt alles zu mystisch wird.
Rolf
--
sumpsi - posui - obstruxi