bobby: PDO problem mit BIT-Werten und prepared Statements

Moin,

folgendes Problem. Ich arbeite mit PDO und prepared Statements

Ich hab mir dazu nen kleinen QueryBuilder gebastelt, der alle Optionen übergeben bekommt.

So übergebe ich (was nicht funktioniert, trotz $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);

$rigths=1111111111111111111111111111111111111111111111111111111111111111;
$queryVars->clause .= " AND (:RIGHTS  & mg.group = mg.group OR kta_modules.modulgroup=0)";
$queryVars->preparedVars[':RIGHTS']=$rights;

Es soll nun über die Bitweise Verrechnung der Rechtevariable mit dem mg.group-Eintrag herausgefunden werden ob das Modul aufgerufen werden darf.

Nun ist das problem, dass die bitweise operation nur dann funktioniert, wenn die rechte entweder als Zahl oder als BitWert übergeben wurden. Auf der DB sind ja 64 Bit möglich. Wenn ich nun die Rechte-Variable in eine Zahl umwandeln möchte kommt irgendwass XXX+E19 raus. Diese wird natürlich von MySQL nicht akzeptiert.

Wenn ich die BIT-Folge direkt übergeben möchte, muss ich dieser ja ein " b' " voranstellen.

Ich könnte nun

$rigths=1111111111111111111111111111111111111111111111111111111111111111;
$queryVars->clause .= " AND (b'".$rights."  & mg.group = mg.group OR kta_modules.modulgroup=0)";

notieren, was aber höchst unsicher ist. Wie bekomme ich es hin, dass entweder eine für MySQL gültige Zahl oder die BIT-Folge direkt an MySQL übergeben kann und dass es sicher ist?

ich habe versucht

$rigths=1111111111111111111111111111111111111111111111111111111111111111;
$queryVars->clause .= " AND (b':RIGHTS  & mg.group = mg.group OR kta_modules.modulgroup=0)";
$queryVars->preparedVars[':RIGHTS']=$rights;
$rigths=1111111111111111111111111111111111111111111111111111111111111111;
$queryVars->clause .= " AND (:RIGHTS  & mg.group = mg.group OR kta_modules.modulgroup=0)";
$queryVars->preparedVars[':RIGHTS']="b'".$rights;

Bitte um Vorschläge.

Gruß Bobby

--
-> Für jedes Problem gibt es eine Lösung, die einfach, sauber und falsch ist! <- ### Henry L. Mencken ### -> Nicht das Problem macht die Schwierigkeiten, sondern unsere Sichtweise! <- ### Viktor Frankl ### ie:{ br:> fl:{ va:} ls:< fo:) rl:( n4:( de:> ss:) ch:? js:( mo:} sh:) zu:)
  1. Moin,

    Manchmal ist die Antwort SOOOOOOO simpel

    $rigths=1111111111111111111111111111111111111111111111111111111111111111;
    $queryVars->clause .= " AND (BIN(:RIGHTS)  & mg.group = mg.group OR kta_modules.modulgroup=0)";
    $queryVars->preparedVars[':RIGHTS']=$rights;
    

    Das scheint die Lösung zu sein....

    Gruß Bobby

    --
    -> Für jedes Problem gibt es eine Lösung, die einfach, sauber und falsch ist! <- ### Henry L. Mencken ### -> Nicht das Problem macht die Schwierigkeiten, sondern unsere Sichtweise! <- ### Viktor Frankl ### ie:{ br:> fl:{ va:} ls:< fo:) rl:( n4:( de:> ss:) ch:? js:( mo:} sh:) zu:)
  2. Tach!

    So übergebe ich (was nicht funktioniert, trotz $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);

    MySQL hat eingebauten Support für Prepared Statements, du musst sie nicht emulieren.

    $rigths=1111111111111111111111111111111111111111111111111111111111111111;
    

    Kann es sein, dass dein Integer hier überläuft, sprich größer als PHP_INT_MAX wird? Und bist

    PHP kennt ab 5.4 auch eine Literalschreibweise für Binärwerte: 0b10101010;

    Nun ist das problem, dass die bitweise operation nur dann funktioniert, wenn die rechte entweder als Zahl oder als BitWert übergeben wurden.

    Was hindert dich an der Übergabe einer Zahl, die deine Bitfolge repräsentiert?

    Wenn ich die BIT-Folge direkt übergeben möchte, muss ich dieser ja ein " b' " voranstellen.

    Ich könnte nun

    $rigths=1111111111111111111111111111111111111111111111111111111111111111;
    $queryVars->clause .= " AND (b'".$rights."  & mg.group = mg.group OR kta_modules.modulgroup=0)";
    

    notieren, was aber höchst unsicher ist.

    Nein, warum? Wenn du eine Zahl garantierst, kann da keine Unsicherheit in Form einer SQL-Injection auftreten.

    ich habe versucht

    $rigths=1111111111111111111111111111111111111111111111111111111111111111;
    $queryVars->clause .= " AND (b':RIGHTS  & mg.group = mg.group OR kta_modules.modulgroup=0)";
    $queryVars->preparedVars[':RIGHTS']=$rights;
    

    Das mixt die Literalschreibweise und Prepared Statement und kann so nicht gehen. Dazu müsste MySQL erstmal die Zahl wieder in ihre Literalschreibweise übersetzen und dann erst das Statement parsen. Das Statement wird aber schon beim Prepare geparst und die Werte kommen erst später. Und zwar mit jedem Execute, wenn du mehrere abfeuerst.

    $rigths=1111111111111111111111111111111111111111111111111111111111111111;
    $queryVars->clause .= " AND (:RIGHTS  & mg.group = mg.group OR kta_modules.modulgroup=0)";
    $queryVars->preparedVars[':RIGHTS']="b'".$rights;
    

    Auch das kann nicht gehen, weil die Werte als Wert und nicht als Literal übergeben werden.

    Bitte um Vorschläge.

    Nimm richtige Zahlen.

    dedlfix.

    1. Moin,

      MySQL hat eingebauten Support für Prepared Statements, du musst sie nicht emulieren.

      habe ich auch schon bemerkt. Diesen Workaround hatte ich nur als möglichen Lösungsansatz in diversen Foren gelesen.

      $rigths=1111111111111111111111111111111111111111111111111111111111111111;
      

      Kann es sein, dass dein Integer hier überläuft, sprich größer als PHP_INT_MAX wird? Und bist

      Das ist das Problem. MySQL kann 64bit für BIT-Datentyp. Mein PHP läuft auf 32 Bit und hat deshalb nen INT-Zahlenüberlauf. Deshalb lasse ich mir die Rechte als Zeichenkette zurückgeben aus der DB oder setze diese händisch als Zeichenkette. Also

      $rigths="1111111111111111111111111111111111111111111111111111111111111111";
      

      Dann übergebe ich die Zeichenkette an das MySQL und interpretiere diese über die BIN() Funktion von MySQL als eine Binäre Zahl. Das funktioniert wunderbar. Ich wollte die Rechtevergabe halt als Bitmaske machen, da mir MySQL mit 64 Bit doch genügend Spielraum lässt. So kann ich 64*64 Module behandeln. Sollte dies zu wenig sein, füge ich noch eine Rechteebene hinzu. (64x64x64)

      PHP kennt ab 5.4 auch eine Literalschreibweise für Binärwerte: 0b10101010;

      Gibt es da nicht auch den Überlauf wenn PHP auf 32 Bit läuft?

      Nun ist das problem, dass die bitweise operation nur dann funktioniert, wenn die rechte entweder als Zahl oder als BitWert übergeben wurden.

      Was hindert dich an der Übergabe einer Zahl, die deine Bitfolge repräsentiert?

      Habe ich nun gemacht. Ich musste MySQL nur sagen, dass dies eine BIT-Folge ist (über die BIN()-Function)

      Wenn ich die BIT-Folge direkt übergeben möchte, muss ich dieser ja ein " b' " voranstellen.

      Ich könnte nun

      $rigths=1111111111111111111111111111111111111111111111111111111111111111;
      $queryVars->clause .= " AND (b'".$rights."  & mg.group = mg.group OR kta_modules.modulgroup=0)";
      

      notieren, was aber höchst unsicher ist.

      Nein, warum? Wenn du eine Zahl garantierst, kann da keine Unsicherheit in Form einer SQL-Injection auftreten.

      Da ist wieder das Problem des Überlaufs (32bit zu 84 bit). Das hatte ich natürlich auch probiert.

      Na und zu den restlichen Versuchen hast du ja alles gesagt.

      Gruß Bobby

      --
      -> Für jedes Problem gibt es eine Lösung, die einfach, sauber und falsch ist! <- ### Henry L. Mencken ### -> Nicht das Problem macht die Schwierigkeiten, sondern unsere Sichtweise! <- ### Viktor Frankl ### ie:{ br:> fl:{ va:} ls:< fo:) rl:( n4:( de:> ss:) ch:? js:( mo:} sh:) zu:)
      1. Tach!

        MySQL kann 64bit für BIT-Datentyp. Mein PHP läuft auf 32 Bit und hat deshalb nen INT-Zahlenüberlauf. Deshalb lasse ich mir die Rechte als Zeichenkette zurückgeben aus der DB oder setze diese händisch als Zeichenkette. Also

        $rigths="1111111111111111111111111111111111111111111111111111111111111111";
        

        Ah, was doch fehlende Anführungszeichen für Unklarheit stiften können.

        PHP kennt ab 5.4 auch eine Literalschreibweise für Binärwerte: 0b10101010;

        Gibt es da nicht auch den Überlauf wenn PHP auf 32 Bit läuft?

        Muss ja.

        Ansonsten wird wohl das BIN() plus Zeichenfolge in deinem Fall die Lösung bleiben.

        dedlfix.

  3. Hallo,

    $rigths=111...111;
    ...
    ...=$rights;
    

    Nur der Vollständigkeit halber: du verwendest zwei unterschiedliche Variablen. Da du dein Problem aber bereits gelöst hast, tust du das wohl nur hier im Forum.

    Gruß
    Kalk

    1. Moin,

      Hallo,

      $rigths=111...111;
      ...
      ...=$rights;
      

      Nur der Vollständigkeit halber: du verwendest zwei unterschiedliche Variablen. Da du dein Problem aber bereits gelöst hast, tust du das wohl nur hier im Forum.

      Du hast natürlich vollkommen recht. Die "Rechte" kommen aus der Datenbank und sind bei den Usergruppen/Rollen hinterlegt und werden entsprechend ausgelesen. Der Fehler ist tatsächlich nur hier im Forum.

      Gruß Bobby

      --
      -> Für jedes Problem gibt es eine Lösung, die einfach, sauber und falsch ist! <- ### Henry L. Mencken ### -> Nicht das Problem macht die Schwierigkeiten, sondern unsere Sichtweise! <- ### Viktor Frankl ### ie:{ br:> fl:{ va:} ls:< fo:) rl:( n4:( de:> ss:) ch:? js:( mo:} sh:) zu:)