Beiträge von cottton

    Stimmt. Hatte letztens überlegt das über die follower zu lösen.

    Das macht ja aber keinen Sinn.

    Jeder kann jemanden folgen (der gefolgte kann sich nicht wehren).

    Aber eine Freundschaft muss bestätigt werden.

    Also neue Tabelle.

    Arnes Ansatz ist schön einfach.

    Das einzigste, was mir noch einfällt wäre,

    dass Du zwei Tabellen nutzt:

    friend_request

    friend

    In friend_request speicherst Du Anfragen.

    Ein Feld created_at gibt an, wann die Anfrage erstellt wurde.

    Nach n Tagen läuft die request dann aus und der Eintrag wird gelöscht.

    (Du brauchst dort eigtl kein Auto increment).

    Wird die request angenommen, wird der Eintrag auch gelöscht.

    Dann aber bekommt die Tabelle friends den gemeinsamen Eintrag.

    Evtl reicht jetzt auch eine Zeile in friends:

    user ID |user id | created_at

    (Kann das nicht zu Ende denken. Bin mehr damit beschäftigt mit dem Tablet zu schreiben ;D

    )

    Zitat

    Warning: session_start() [function.session-start]: Cannot send session cookie - headers already sent by (output started at /users/sebastian1012/www/homepagebasti1012/chat/eigener_chat/php/profil.php:2) in /users/sebastian1012/www/homepagebasti1012/chat/eigener_chat/php/profil.php on line 5

    Das wäre dann der Fehler, den Du hättest posten können.

    Cannot send session cookie - headers already sent -- headers werden gesendet, sobald das erste Zeichen an raus geht (gesendet wird).

    by (output started at -- output|Ausgabe (echo, var_dump, ...) started at ...

    session_start muss immer ausgeführt werden, bevor das erste Zeichen ausgegeben wird.

    Was Stef sagt. Was wollen wir mit geändertem Code?

    Fehler ist ON.

    Das ist ein reserviertes Wort.

    Bsp: JOIN `tbl` AS `foo` ON (...)

    Also immer (und das sage ich auch immer wieder) die Table, Column, und Alias in `` stellen.

    Man sollte aber auch aussagekräftige Namen verwenden. "ON" Sagt mir nichts. Wenn es "online" sein soll, dann nenne es doch online.

    Was Arne Drews sagt und -


    EDIT: hab hier Mist über LIMIT geschrieben :D nicht beachten - werd ich asap ändern.


    SELECT ... WHERE ... LIMIT 1;

    wird nur einen Datensatz ausgeben.

    Der 2te Parameter nach dem Komma ist dass OFFSET.

    SELECT ... WHERE ... LIMIT 1, 5;

    Gib mir eine row und skippe die ersten 5.

    SELECT ... WHERE ... ORDER BY `id` DESC LIMIT 1;

    Gib mir eine row, sortiert bei id DESC. Bei Einträgen mit ids 1, 2, 3, 4 und 5 wird die 5te row ausgegeben.

    SELECT ... WHERE ... ORDER BY `id` DESC LIMIT 1, 2;

    Gib mir eine row, skipped die ersten 2, sortiert bei id DESC. Bei Einträgen mit ids 1, 2, 3, 4 und 5 wird die 4te row ausgegeben.

    Platzhalter

    Über bindParam() kannst Du angeben, als was die Value in die Query eingefügt werden soll.

    Du könntest per bindParam() einen String ("5") übergeben - der wird dann aber als Integer eingefügt.

    Ohne bindParam() - also die Parameter per execute übergeben - werden die Values default immer als String in die Query eingefügt.

    Gibst Du also ein array('limit' => 5) als integer rein, wird trotzdem (default) ein String eingefügt.

    Stell Dir die Query als Template vor (hier ganz gut beschrieben: http://php.net/manual/de/pdo.prepared-statements.php).

    Du gibtst an, dass :hier eine Value eingefügt werden soll - im Bsp "Foo".

    Per PHP übergibst Du die Value für :hier an execute().

    Jetzt kommt PHP daher und ersetzt den Platzhalter :hier mit der Value "Foo".

    Dabei Nimmt er den String

    SELECT * FROM tbl WHERE col = :hier

    und setzt an die Stelle :hier den String 'Foo' (inclusive der ' einfachen Anführungszeichen)

    SELECT * FROM tbl WHERE col = 'Foo'

    Per bindParam() können wir aber sagen: ich will, dass Du die Value als Integer einfügst.

    Dann bekommt die Value keine Anführungszeichen, weil ... naja, Integer halt :) .

    Das einfügen der Values kann PHP (Treiber http://php.net/manual/de/pdo.drivers.php) oder auch der MySQL Server übernehmen (Siehe MySQL Prepared Statements.).

    Bei PHP erledigt das der Treiber. Also wird intern die Query prepared und dann an den MySQL Server geschickt.

    Man kann das, glaub ich mal gelesen zu haben, auch umstellen, dass man das den MySQL Server erledigen lässt.

    Aber das ist sehr weit weg vom Thema :)

    Du kannst beides mixen - bindParam() und zusätzlich Parameter per execute() übergeben.

    Wichtig ist bindParam() immer dann, wenn Du nur einen bestimmten Typ (String, Integer, ...) übergeben soltlest.

    Und das ist der Knackpunkt bei LIMIT, denn das akzeptiert nur ganze Zahlen ohne Anführungszeichen.

    SELECT ... FROM ... LIMIT '1', '5'; ist nicht valid.


    Zu Deinem Script: ich glaub ich weiß jetzt, was Du willst.

    Du willst die Links

    << Previous [1][2][3][4][5] Next >>

    darstellen. Das aber dynamisch, damit sowas nicht passiert:

    << Previous [1][2][3][4][5][6][7][8][9][10][12][13][14][15]... Next >>

    sondern:

    << Previous [5][6][7][8][9] Next >>

    Das hab ich gerade mal versucht - bekomm ich gerade net hin :D

    Ist zu lange her.

    Verstehe das Problem gerade gar nicht.

    Aber ich glaube, Du machst es Dir zu kompliziert.

    Wenn ich Dich richtig verstehe, willst Du die eigentliche Pagonation bauen.

    Das Grundprinzip ist eigtl ganz einfach:

    Transaktionssicherheit. Dabei geht es nicht um Geschwindigkeit.

    Du stellst damit sicher, dass alle Queries wirklich durchgingen.

    Bsp.:

    Du willst mit der ersten Query eien User anlegen.

    Mit der zweiten Query in eine andere Tabelle seine Daten speichern.

    Ohne Transaction:

    Per Transaction stellst Du sicher, dass alles, oder nichts gespeichert wird:

    PHP (PDO) spielt hier eher eine Mittelsman Rolle.

    Du kannst Dir das so vorstellen, dass:

    - startTransaction: PHP sendet den MySQL Befehl "START TRANSACTION" and den MySQL Server

    - PHP sendet erste Query an den MySQL Server (der Server notiert sich das, die Daten sind aber noch nicht live)

    - PHP sendet zweite Query an den MySQL Server (der Server notiert sich das, die Daten sind aber noch nicht live)

    - commit: PHP sendet den MySQL Befehl "COMMIT" an den MySQL Server (der Server schließt die Transaktion ab und die Daten sind live)

    order

    - rollback: PHP sendet den MySQL Befehl "ROLLBACK" an den MySQL Server (der Server verwirft alle notierte Änderungen. Nichts wurde an den Daten geändert).

    https://dev.mysql.com/doc/refman/8.0/en/commit.html

    Wichtig zu wissen ist: startest Du eine Transaktion und sendest nie ein COMMIT, dann verwirft der MySQL Server alle Änderungen.

    Und das ist gut. Denn es könnte ja zB sein, dass das Script abgekackt ist (zB Fatal Error).

    Das kannst Du austesten:

    - erstelle einfaches Script

    - starte die Transaktion

    - update irgendwas (oder insert, ...)

    - lasse das Script beenden (die; oder exit;)

    Es wird nichts an den Daten geändert worden sein.

    Mir fällt da noch was ein.

    Du solltest alle INSERTs über eine TRANSACTION in die db schieben.

    Denn entweder alle Empfänger werden eingetragen, oder keiner.

    An sich eigtl alles, was die Message betrifft - auch die Message selbst.

    messageId (INT) senderId (INT) empfaengerId (INT)
    1 1 2
    1 1 3
    1 1 4
    1 1 5
    1 1 6
    1 1 7

    Eine Message hat einen Absender (1:1).

    Eine Message hat n Empfänger (1:n).

    Für jeden Empfänger gibt es einen Eintrag.

    Code
    // pseudo code
    message = "Hallo, ..."
    senderId = user[id] // absender / eingeloggte user
    receiverIds = $_POST[receiver_id] // checkbox array (<input type="checkbox" name="receiver_id[]" />)
    
    foreach recceiverIds as receiverId
        INSERT INTO tbl SET ...

    :)

    Bitte kein VARCHAR für Datum.

    Und bevor ichs vergesse: isDeleted solltest Du vom Typ TINYINT setzen. Das spart Platz (nur 1 Byte statt 4 - siehe https://dev.mysql.com/doc/refman/5.7/en/integer-types.html).

    Wenn Du nur Jahr, Monat und Tag speichern willst, dann DATE.

    Wenn die Du die Zeit auch speichern willst, dann DATETIME.

    Wenn Du einen Zeitstempel speichern willst, dann TIMESTAMP.

    Unterschiede:

    DATE

    used for values with a date part but no time part.

    'YYYY-MM-DD' format

    range is '1000-01-01' to '9999-12-31'

    DATETIME

    used for values that contain both date and time parts.

    'YYYY-MM-DD HH:MM:SS' format

    range is '1000-01-01 00:00:00' to '9999-12-31 23:59:59'

    TIMESTAMP

    used for values that contain both date and time parts.

    'YYYY-MM-DD HH:MM:SS' format

    '1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07' UTC

    INFO: nutze keinen TIMESTAMP wenn das Datum vor 1970 liegen kann. Im Zweifel immer DATETIME.

    EDIT: auch nicht, wenn zB ein Termin nach 2038-01-19 03:14:07 sein kann. Wenn das Tool|Website dann noch läuft, oder wir alle noch existieren :D

    Siehe: https://dev.mysql.com/doc/refman/5.7/en/datetime.html

    Und hier ist Dein Problem mit CURRENT TIMESTAMP - DATE akzeptiert keine Zeitangabe.

    Es hätte also zB "2018-04-18 12:00:00" in ein DATE Feld gespeichert werden sollen, dass nur "2018-04-18" aufnehmen kann.

    0000-00-00 wurde gespeichert, weil es keine DEFAULT value gab. Dann ist DATE "leer" 0000-00-00. DATETIME wäre "0000-00-00 00:00:00".

    Das sollte man aber vermeiden. Schon alleine weil es laut Docu nicht valid ist (siehe "range").

    Und Achtung: Du kannst auf das Feld deletedAt kein DEFAULT CURRENT TIMESTAMP setzen.

    Für den MySQL Server hieße das, dass bei einem neuen Datensatz (INSERT INTO) das Feld auf, naja, den momentanen Zeitstempel gesetzt wird.

    Alle neuen Datensätze wären also default (per Datum|Zeit) als gelöscht markiert.

    Setze deletedAt als DEFAULT NULL. Das heißt, dass es keinen Wert haben muss.

    Und NULL verschwendet keinen Platz.

    Hast Du richtig gedacht.

    Nennt sich Soft Delete.

    (google physical|hard deletion vs logical|soft deletion)

    Man müsste sich nur Dedanken machen, was man dann alles damit machen will.

    Musst Du zB irgendwann wissen, wann der Eintrag gelöscht wurde?

    Du kannst 2 Felder nutzen:

    SQL
    `is_deleted` TINYINT unsigned DEFAULT '0',
    `deleted_at` DATETIME DEFAULT NULL

    Oder nur das Feld `deleted_at`. Dann kannst Du beim SELECT angeben WHERE ... AND `deleted_at` = null;

    PHP
    $date = '2018-04-18 12:00:00';
    $datum = new DateTime($date);
    var_dump($datum->date); // Undefined property: DateTime::$date (::date existiert noch nicht)
    var_dump($datum); // hier wird wohl intern eine art toString method getriggered. Und die setzt dann ::date
    var_dump($datum->date); // ::date ist jetzt vorhanden

    Du solltest besser $datum->format('Y-m-d H:i:s') verwenden.

    EDIT: Dein db Feld `datum` ist sicher vom Typ DATETIME. Dann solltest Du auf jeden fall das db-Format nutzen: Y-m-d H:i:s

    WHERE datum >= DATE_SUB(datum, INTERVAL 12 DAY)");

    übersetzt

    Code
    -- im bsp ist datum in der row gesetzt auf 2018-04-16 00:00:00
    WHERE '2018-04-16 00:00:00' >= 2018-04-16 00:00:00 - 12 tage
    -- also
    WHERE '2018-04-16 00:00:00' >= 2018-04-04 00:00:00

    Das ist immer true.

    Code
    -- entweder du willst direkt von JETZT 12 tage zurück
    WHERE datum >= DATE_SUB(NOW(), INTERVAL 12 DAY)");
    -- oder von einem bestimmen datum
    WHERE datum >= DATE_SUB(:date, INTERVAL 12 DAY)"); -- beachte :date platzhalter

    EDIT

    Falls Du ein :date direkt angibst, könntest Du auch ohne DATE_SUB auskommen.

    SQL
    SELECT '2018-04-16 00:00:01' >= '2018-04-16 00:00:00';

    Ist true. (Ich weiß es gerade nicht 100% aber von der Logik her werden die Werte als Strings verglichen. Und ...01 ist größer als ...00)

    Code
    WHERE datum >= :date;

    Dann sollte aber :date und das Format in der db immer gleich sein.

    Verstehe. Bekomm ich allerdings auch gerade nicht hin.

    Ich probiers mal weiter. Nervt mich gerade, dass ich das nicht hinbekomme :D

    Falls Du es hast, sag mal bescheid :)

    EDIT: foreign key ist eine Beziehung zwischen Spalten in|über Tabellen (hinweg).

    Im Bsp:

    SQL
    CONSTRAINT `fk_user_id`             -- name (wie bei einem index halt der name)
            FOREIGN KEY (`user_id`)     -- in dieser tabelle das feld user_id
            REFERENCES `user` (`id`)    -- hat eine reference in der tabelle user mit dem feld id
            ON UPDATE CASCADE           -- wenn die reference geupdated wird, dann update auch diese tabelle 
            ON DELETE RESTRICT,         -- wenn die reference gelöscht wird, dann verweigere das löschen

    Gibt im Netz sicher bessere Beschreibungen.

    Im Grunde stellst Du damit sicher, dass (im Bsp Deiner Tabellen) in der user table kein user gelöscht wird, der noch in der follow table benutzt wird.

    Nur am Rande:

    man könnte jetzt eine delete-Query daraus machen.

    Das hätte aber den Nachteil, dass Du nicht weißt, welche id nicht gelöscht werden konnte

    (wenn zB nicht existiert ...).

    Wenn aber sehr viele Einträge gelöscht werden können, dann wäre das aber zu empfehlen. Sonst rennt der SQL Server sich müde :D

    Aber auf jeden Fall per transaction:

    Ich sehe|verstehe gerade, dass Du mehrere löschen lassen willst.

    Also ein mass-delete.

    Dann solltest Du aber checkbox verwenden, und nicht button (es sei denn da steckt JS dahinter und Du kannst per button mehrere selecten - sieht aber nicht danach aus).

    Also checkbox verwenden.

    <input type='checkbox' name='ids[]' value='{ID ...}' />

    Einfach mal im Netz suchen nach html multiple checkbox array.

    Im Script checkst Du dann, ob es eine delete-Request ist $_POST[deleteTermin]

    und gehst foreach $_POST[ids] as $id durch und löscht.