Beiträge von cottton

    Passwörter werden NIEMALS in Klartext gespeichert!

    Sieh Dir das hier an: Loginpasswort richtig hashen - password_hash() & password_verify()


    Ich empfehle Die wirklich PDO statt mysqli zu nuten.

    Das ist mMn einfacher und besser documentiert.

    PDO: https://www.php.net/manual/de/book.pdo.php


    Nutze niemals Variablen in der sql-query! (egal ob mysqli oder PDO).

    Stichwort: "SQL-Injection" (google).


    Zum Ablauf: hier mal ein Rohes Bsp. mit Comments

    1st: Such mal im Netz nach "SQL-Injection". Dabei geht es um Sicherheit.

    Nutze Prepared Statements: https://www.php.net/manual/de/pdo.prepared-statements.php

    Nutze nicht ->query().


    ---

    Du hast 2 Abschnitte:

    - $s3->putObject() , was wohl ein Upload zu Amazon ist

    - INSERT INTO ..., was Dir die Infos zu dem File in Deine db schreibt


    Du kannst den Ablauf (in diesem Fall) umdrehen.

    Was mir als erstes auffällt:

    PHP
    1. for ($j=1; $j <= $anzahlzeilen; $j++) {
    2. echo "<button class='tablinks' onclick='wohnungtab(event, '$j')'>Wohnung $j</button>\n";
    3. }

    die Anführungsstriche.

    Code
    1. onclick='
    2.     wohnungtab(
    3.         event,
    4.         '$j' <-------------
    5.     )
    6. '

    ergibt

    HTML
    1. onclick='wohnungtab(event, '1')'

    sollte aber zB

    HTML
    1. onclick='wohnungtab(event, 1)'
    2. <-- oder -->
    3. onclick='wohnungtab(event, "1")'
    4. <-- oder -->
    5. onclick='wohnungtab(event, \'1\')'
    6. <-- ungetested =) -->


    Sonst kann ich auch keinen Fehler sehen.

    Stichwort: SQL-Injection


    ->query()würde ich an Deiner Stelle gleich wieder vergessen.


    Nutze prepared statements: https://www.php.net/manual/de/pdo.prepared-statements.php


    PHP
    1. $dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
    2. // user in users? tabelle sollte `user` heißen, und das feld `name`. Also `user`.`name`
    3. $stmt = $dbh->prepare("SELECT * FROM `users` where `user` = :uname;");
    4. $stmt->execute(['uname' => $uname]);
    5. // siehe https://www.php.net/manual/de/pdostatement.fetch.php
    6. // um rows zu ziehen (fetch)

    Eine andere Möglichkeit wird es nicht geben,

    Bestimmte Werte (wie zb die post max size usw) können nur aus der ini kommen.

    Das script läuft bereits und PHP hat schon mit den Werten "gearbeitet".


    Hier schreibt jemand per .htaccess könnte es gehen: https://stackoverflow.com/a/2773543/3411766


    Du kannst auf jeden Fall die Werte lesen.

    Lass Dir doch mal ausgeben, was die MAX-Werte sind.


    Falls Du nicht an die ini ran kommst,

    dann wäre der nächste Schritt um das Problem relativ schnell zu lösen: den Upload (die Datei) aufteilen.

    DUPLICATE - das heißt, dass ein Feld UNIQUE ist|war.


    Aber ohne genauer Fehlermeldung, kann man nur raten.

    Und ein SHOW CREATE TABLE `my_tbl_name` wäre auch nicht verkehrt.


    Ein FK kann n mal vorkommen, solange er keinen UNIQUE INDEX bekommt.

    FK "sagt nur", dass es in der Haupttabelle einen Eintrag mit der Value in der betreffenden Zeile geben muss.


    Im Bsp hat user mit id 1 drei Einträge - also 3 Adressen.

    User 2 nur eine.

    User 3 (noch) keine.


    Mit einem Foreign Key auf user_id wird es nicht möglich sein,

    in tbl user_address eine Zeile mit user_id 4 einzutragen.

    Denn es gibt keinen user mit id 5 in der Tabelle user.

    Ohne den Code, oder was er macht, angesehen zu haben


    Du nutzt eine Variable $New in der Funktion, die nicht existiert (in dieser Funktion --also in diesem Kontext).


    Der Aufruf passiert wohl hier:

    Code
    1. $New = new ClassProveContakt2();
    2. $New -> tabelle();

    Ein Fix wäre, das Object $New beim Funktionsaufruf mitzugeben:

    Ändere die Funktion - sie bekommt einen Parameter

    Code
    1. function tabelle($New) {
    2. $sb =$New->getMessages();
    3. // ...
    4. }
    5. // oder
    6. // function tabelle(ClassProveContakt2 $New) {...}
    7. // oder (falls es eine abstract class gibt)
    8. // function tabelle(AbstractClassProveContakt $New) {...}
    9. // oder (falls es ein interface gibt)
    10. // function tabelle(SoUndSoInterface $New) {...}


    Und den Aufruf:

    Code
    1. $New = new ClassProveContakt2();
    2. $New -> tabelle($New);

    Sollen User getracked werden, die registriert sind, oder alle User?

    Wenn alle, dann brauchst Du einen Browser-Fingerprint (Hab mich lange nicht mehr damit beschäftigt. Aber such mal im Netz).

    Anhand von dem Fingerprint (was ja am Ende ein Hash ist)

    kannst Du dann pro User n Einträge seines Browsers ect anlegen.


    Bsp.:

    Bei jedem Seitenaufruf prüfst Du, ob der Fingerprint in `anon_user` schon existiert - sonst anlegen.

    Bei jedem Seitenaufruf prüfst Du, ob der Browser in `browser` schon existiert - sonst anlegen.

    ---

    Jetzt könntest Du bei jedem Seitenaufruf in `anon_user_browser` eine neue Zeile einfügen.

    Dann hättest Du eine genaue Übersicht, welcher user mit welchem Browser reinkam.

    ABER das solltet Du nicht!

    Bei einem Angriff bei dem Deine Seite sehr oft aufgerufen wird, ist die Tabelle schnell voll.


    Du könntest das Ganze jetzt auf "pro Minute" oder "pro Stunde" runterdrücken.

    Aber das bedeutet (noch) mehr Aufwand.


    Wenn der Aufwand egal ist, dann:

    So, nu hättest Du also schon mal die Tabellen mit dem Browser und den Usern up-to-date.

    Geht evtl auch nocht sinnvoller.


    Du kannst ja jetzt aber nicht einfach immer wieder eine Zeile in `anon_user_browser` einfügen.

    Das erste, was mir da einfällt: Du brauchst es sicher nicht Sekundengenau.

    Also kannst Du das created_at schon mal runterdrücken auf "Jahr-Monat-Tag Stunde-Minute" (Y-m-d H:i).

    created_at könnte man dann auch umbenennen in ~"interval".


    Dazu kommt jetzt noch ein Feld `count`.

    Das Ziel:

    gibt es zu der momentanen Minute schon einen Eintrag, dann update den count +1.

    sonst insert new row mit count 1.


    Ob das Ganze jetzt Sinn macht (Aufwand<=>Nutzen), weiß ich nicht.

    Außerdem schiebst du Daten in die Datenbank, ohne diese zu escapen

    Falsche Wortwahl und|oder Du hast da evtl. auch was falsch verstanden.

    XSS passiert bei der Ausgabe (Browser).

    Hier ist aber schlimmer, dass er Userdaten direkt in eine SQL Query packt. Das schreit nach SQL-Injections.


    Daten gehören nicht escaped in die db. Aber es sollte auf keinen Fall eine Query "zusammengebastelt" werden.


    ado683 Nutze mysqli_ (oder PDO) mit Prepared Statements https://www.php.net/manual/de/…t.prepared-statements.php .

    Und htmlspecialchars() um die Daten auszugeben https://www.php.net/manual/de/function.htmlspecialchars.php .

    Keine Ausnahmen!


    Nutze === statt == .


    Was zu Hölle ist das: $_SESSION["password"] ?

    Ich hoffe, Du speicherst nicht wirklich pws in der Session. Die landen ungehasht und unverschlüsselt in Dateien auf Deinem Server (default in /tmp/).


    Auch das hier geht gar nicht: $sqlab .= " password = '" . $_POST[ "passwordUser" ] . "',";

    Passwörter gehören gehasht in die db!

    Nutze password_hash() und pasword_verify(). Siehe Loginpasswort richtig hashen - password_hash() & password_verify() .


    ---

    Um doppelte Einträge zu vermeiden, sollte (wie Du schon sagtest) ein unique index genutzt werden.

    Damit man nicht jedes mal in den SQL Fehler rennt (duplicate ...), sollte man vor dem Update ein SELECT ausführen.

    Wird zB der Name gefunden, dann existiert er offensichtlich und man kann einen Fehler ausgeben.

    Naja, Du sendest ja die Form ab, um den User zu bearbeiten -

    dann musst Du schon mitgeben, wen Du bearbeiten willst.


    $dsatz['id'] hast Du noch vom letzen Loop. Und da Du prüfst, ob es nur einen gibt, kannst Du diesen (last) User nutzen.

    Könnte man aber auch schöner aufbauen =)


    EDIT: nutze htmlspecialchars() um Ausgaben zu maskieren!

    EDIT2: Du könntest die ID auch per GET in der URL migeben. Also dann nicht mehr als POST hidden field.

    Ein Increment Script|Tool schreiben ist spannend, weil Du zB beachten musst,

    dass es gleichzeitige Zugriffe auf die Datenbank gibt.


    Mal angenommen Du hast eine normale Website mit Kunden.

    Jeder Kunde bekommt eine Kundennummer - in etwa: T-0001  (T hat hier keine Bedeutung. Soll nur zeigen, dass es einen Prefix geben können muss).


    Zwei Kd kommen gleichzeitig auf Deine Seite und registrieren sich.

    Nun musste Du sicherstellen, dass die Nummer einmalig bleibt.

    Dass machst Du als erstes hart über einen uidx (unique index) in der Datenbank.

    Es ist jetzt also schon mal nicht möglich, die gleiche Nummer "ausversehen" zu speichern.


    Wie stellst Du nun sicher, dass Du eine eeinzigartige Nummer bekommst?

    Ich gehe im Bsp nur von einer Nummer aus - ohne Prefix.

    Code
    1. // pseudocode
    2. // kunde A registriert sich:
    3. lastNumber = SELECT MAX(`number`) FROM `increment`; // die größte (zu letzt erstellte) nummber laden
    4. newNumber = lastNumber + 1; // eine neue nummer für den neuen kd
    5. // neue nummer für den kd einfügen
    6. INSERT INTO `increment` SET `number` = :new_number; // usw - zB per PHP PDO ...


    Soweit ... easy?

    Nope.

    Der gleiche Ablauf jetzt mit einem dicken fetten Haken:

    Mal angenommen Du hattest als letzte Nummer die 5 in der db,

    dann würdest Du für Kd A auf 6 hochzählen.

    Da aber - bevor Du Kd A gespeichert hast - Kd B sich auch registrieren will,

    bekommst Du für Kd B auch die 6.


    Ich hoffe, ich konnte es einigermaßen verdeutlichen.


    Was kann man da machen?

    Antwort: Die Datenbank hält die Nummer, also zählt die Datenbank die Nummer hoch. Nicht etwa das PHP Script.


    Bsp:

    Per PHP erste Query abschicken, um die Nummer zu erhöhen

    und die neue Nummer in eine Session Variable ablegen (denn UPDATE gibt uns keine Daten zurück):

    SQL
    1. UPDATE `incremnt` SET `number` = @next_session := `number` + 1;

    Jetzt eine zweite Abfrage, um die Session Variable zu lesen:

    SQL
    1. SELECT @next_session;


    Ich hab das Problem (umfangreicher natürlich) für meinen Arbeitgeber gelöst.

    Kann aber den fertigen Code nicht posten (klar).


    Aber aus der docu:


    Das war jetzt nur ein einfaches Beispiel.

    Wenn es nun aber noch mehrere Nummern (increments) geben soll - zB für user, invoice, creditmemo, ... - dann brauchst Du:

    - einen Prefix (zB O-xxx für Order, I-xxx für Invoice, ...)

    - im besten Fall eine Tabelle für alle increments

    - options wie zB Länge


    So hättest Du dann eine Tabelle für mehrere increments.

    Code
    1. beispiele:
    2. O-00054         prefix: O-    "current" or last_increment": 54    length: 7
    3. C-0421          prefix: C- "current" or last_increment": 421 length: 6
    4. K-0000004631    prefix: K- "current" or last_increment": 4631 length: 12


    Spannend =)

    ----


    Über Transactions: was @m.scatello meinte.

    Was in dem Link aber per SQL gemacht wird (START TRANSACTION, COMMIT und ROLLBACK) wird dann aber besser per PHP gesteuert.

    Siehe: https://www.php.net/manual/de/pdo.begintransaction.php

    Die Befehle wie zB "START TRANSACTION" übernimmt dann PDO für Dich.

    mit "mehrfach: nein" meinte er,

    dass es für diesen einen user (mit ID x) keine Mehrfachdaten gibt. Also kein Details Table.


    im prinzip habe ich schon bissl zeit, denn ich bin "nur" praktikant und will es vernünftig machen, da dies mein projekt für die IHK ist.

    Na dann ordentlich =)

    Und Du kannst es ja Stück für Stück durchgehen.





    Würde erstal mit dem (logisch) user tbl anfangen,

    dann den address tbl.

    Dann hast Du schon mal ne Basis.

    user.increment (Kundennummer) ist ein spannendes Thema. aber Dazu findest Du recht viel im Netz =)


    Wichtig: egal wie viele Tabellen Du am Ende nutzt - INSERT eines neuen Nutzers (und "größere" UPDATEs) immer per TRANSACTION.

    Yap, was m.scatello sagt.

    Im Prinzip kann man es ja schon lesen, ob es eine extra Tabelle geben wird.


    Z.B. "Kommentare" - Mehrzahl. Also viele :)


    Die erste Fragen sind aber immer:

    - wie schnell muss es fertig sein

    - wie viele Einträge werden erwartet


    Man könnte ja ein richtig schönes System aufbauen. Allerdings musste ich lernen, dass man in keine Zeit für schönen Code hat (weil es Dir keiner bezahlt :D ).


    Bsp:

    Ein Ansprechparter ist ein user.

    Er bekommt eine Rolle als Ansrechpartner.

    Er kann mehrere andere user als Kunden betreuen.

    Er kann mehrere Addressen haben.

    Er kann mehrere Telefonnummern haben.

    (...)


    Hier im Bsp wäre es schön, wenn man viele viele Detail-Tabellen hätte.

    Code
    1. tbl user                main table
    2. tbl user_role           1:n (user:user_role)
    3. tbl user_address        1:n
    4. tbl user_telefon        1:n

    Usw.


    Muss es also schnell gehen, dann bau Dir erstmal ein funktionierendes System.

    Aber immer im Hinterkopf, dass Du hier und da module relativ einfach erweitrn kannst.


    Beisp.: addresse erstmal direkt in die user table.

    Beim Laden des users dann aber immer eine Methode (function|class|model|helper) benutzen.

    Sollte man dann doch mehrere Addressen benötigen,

    dann kann man die neue Tabelle erstellen, die Daten rüber kopieren, und die Methode zum Laden erweitern (zB per JOIN).

    Nehmen wir an, wir haben eine php welche verschiedene Aufgaben im gleichem Themenbereich erledigt. Um herauszufinden, welche Aufgabe erledigt werden muss, werden post Variablen per AJAX übermittelt. Nun brauche ich die Datei

    Welche Datei?


    Fals Daten gemeint ist, dann verstehe ich das so:

    Kann ich aber nicht empfehlen.

    Was auch immer in der 2ten (b.php) PHP-Datei gemacht werden soll,

    sollte besser in eine Funktion (Helper, ...) gepackt werden und per Parameter aufgerufen werden:


    Was scatello sagt oder gleich ne min-length bestimmen.

    Code
    1. $minLength = 3;
    2. if(isset($_POST['search']) and strlen($_POST['search']) >= $minLength){
    3. // ...
    4. }


    EDIT: und natürlich Leerzeichen am Anfang and Ende entfernen

    Code
    1. $minLength = 3;
    2. $search = '';
    3. if (isset($_POST['search'])) {
    4. $search = trim($_POST['search']);
    5. }
    6. if (strlen($search) >= $minLength) {
    7.     // ... ab hier gehts weiter - aber nutze $search, nicht mehr $_POST['search']
    8. }
    Code
    1. Ich würde es gerne verstehen

    Sehr gut!


    Man schreibt keine Variablen in die Query.

    Das sind Sicherheitslücken.

    Suche mal im Netz nach "SQL injections".


    Wenn Du Platzhalter (richtig) verwendest, dann ist eine SQL-Injection praktisch ausgeschlossen.


    Bsp:

    SQL
    1. SELECT * FROM `users` WHERE `trackingid` LIKE ?;

    ? ist hier ein Platzhalter.

    Bei der Ausführung übergibst Du dann die Values für die Platzhalter:

    PHP
    1. $stmt = $pdo->prepare("SELECT * FROM `users` WHERE `trackingid` LIKE ?;");
    2. $stmt->bindValue(1, "%{$search}%", PDO::PARAM_STR);
    3. $stmt->execute();

    Oder:

    PHP
    1. $stmt = $pdo->prepare("SELECT * FROM `users` WHERE `trackingid` LIKE :search;");
    2. $stmt->execute(
    3. array(
    4. 'search' => "%{$search}%"
    5.         // die doppelpunkte muss man nicht mit angeben, kann man aber:
    6. // ':search' => "%{$search}%"
    7. )
    8. );
    9. // info: mit execute übergebene parameter werden immer als string eingefügt

    Siehe: http://php.net/manual/de/pdost…tatement.execute-examples



    Du hast es schon richtig gehabt, hast dann aber ::bindValue übergangen, in dem Du die Value direct in die Query geschrieben hast.

    Hätte von PHP eigtl einen Fehler erwartet - ~"number of parameters bound to ... does not match ...".




    Zur 2ten Frage:

    ALLE DATEN SIND BÖSE! <<--- merken =)

    $_POST, $_GET, aus Dateien, selbst in Deiner eigenen Datenbank ...

    alle Daten müssen als böse betrachtet werden.


    Bsp Browserausgabe:

    Alles mit (zB) htmlspecialchars() maskieren.

    PHP
    1. <?php
    2. // some code ...
    3. ?><div><?php echo htmlspecialchars($results['id']) ?></div>
    4. <div><?php echo htmlspecialchars($results['email']) ?></div>
    5. ?>
    6. // ...


    Mal angenommen ich hab beim Registrieren als email

    Code
    1. <script>alert('lulz');</script>

    angegeben. Und aus irgendeinem Grund ging das so in Deine db. (Oder jemand hatte zugriff auf die db ... wie auch immer...)

    Dann würde der Browser das hier bekommen:

    PHP
    1. <?php
    2. // some code ...
    3. ?><div>1</div>
    4. <div><script>alert('lulz');</script></div>
    5. ?>
    6. // ...

    ... und JS wird ausgeführt.



    ---

    Also:

    Alle Daten sind böse.

    SQL nie mit Variablen direkt füttern, sondern Platzhalter verwenden.

    HTML-Ausgaben immer mit zB htmlspecialchars() maskieren.

    Du müsstest eigtl. ein Fehler bekommen.

    Du bindest den Param `$search` aber schreibst ihn direct in die Query.


    KEINE VARS in die Query!


    SQL
    1. select * from users where trackingid LIKE :search LIMIT 0 ,10;
    2. -- oder
    3. select * from users where trackingid LIKE ? LIMIT 0 ,10;