hawkmaster: PDO connect MS SQL Server?

Hallo zusammen,
Bisher hatte ich immer mit PDO und MySQL gearbeitet.
Nun versuche ich eine Verbindung zu einem SQL Server 2008 Express herzustellen.

Ich versuche es so:
$MSSQL['HOST'] = '127.0.0.1\SQLEXPRESS';
$MSSQL['USER'] = 'MyWindowsUserName';
    $MSSQL['PWD'] = 'MyWindowsPassword';
    $MSSQL['DB'] = 'newsqldatabase';

$DBO = new PDO('mssql:host='.$MSSQL['HOST'].';dbname='.$MSSQL['DB'].'', $MSSQL['USER'], $MSSQL['PWD']);

Es kommt aber die Meldung:
Error!: SQLSTATE[28000] Login incorrect. (severity 2)

Ich suche schon den ganzen Tag nach einer Lösung und google wie der wilde.
Habe auch schon die neueste

ntwdblib.dll
geladen.
wie auf http://www.php.net/manual/de/ref.pdo-dblib.php empfohlen.

Wie ist das mit der Authentifizierung bei MS SQL? Muss man als user den Windows User angeben und das Windows Anmeldepasswort?

bin für jeden Tipp dankbar

vielen Dank und viele Grüße
hawk

  1. Hi!

    Error!: SQLSTATE[28000] Login incorrect. (severity 2)
    Ich suche schon den ganzen Tag nach einer Lösung und google wie der wilde.

    Hast du schon PDO_ODBC nebst einer konfigurierten ODBC-Verbindung probiert? Das PHP-Handbuch schreibt, dass PDO_MSSQL experimentell sein und empfiehlt die ODBC-Variante. Außerdem: http://de.php.net/manual/en/ref.pdo-dblib.php#66917

    Lo!

    1. Hallo dedlfix,
      danke für deine Hilfe.
      Nach weiteren Stunden ausprobieren habe ich es jetzt mit ODBC probiert.
      Also der ODBC Treiber ist installiert und die Verbindung klappt.

      Aber von PHP bzw. PDO aus klappt es noch nicht so:

      1. Versuch:
      $DBO = new PDO("odbc:Driver={SQL Server};Server={$MSSQL['HOST']};Database={$MSSQL['DB']};Uid={$MSSQL['USER']};Pwd={$MSSQL['PWD']}",$MSSQL['USER'], $MSSQL['PWD']);

      Das bringt dann nach kurzer Zeit:

      "Error!: SQLSTATE[08001] SQLDriverConnect: 17 [Microsoft][ODBC SQL Server Driver][Shared Memory]SQL Server existiert nicht oder Zugriff verweigert."

      Wenn ich es so versuche:
      $DBO = new PDO('odbc:MyODBCName');

      erscheint;
      Error!: SQLSTATE[42000]: Syntax error or access violation: 102 [Microsoft][ODBC SQL Server Driver][SQL Server]Falsche Syntax in der N�he von ':'. (SQLExecute[102] at ext\pdo_odbc\odbc_stmt.c:133)

      vielen Dank und viele Grüße
      hawk

      1. Hi!

        danke für deine Hilfe.

        So richtig kann ich dir vielleicht nicht helfen, weil ich mit PDO_MSSQL/PDO_ODBC keine Erfahrung habe.

        Nach weiteren Stunden ausprobieren habe ich es jetzt mit ODBC probiert.

        Der kleine Tipp mit dem localhost,1433 hat auch nichts gebracht?

        Also der ODBC Treiber ist installiert und die Verbindung klappt.
        Aber von PHP bzw. PDO aus klappt es noch nicht so:

        Wo läuft denn dein PHP? Unix-Maschine? Wenn du von ODBC-Treiber installieren sprichst, müsste man das annehmen. Unter Windows beschränkte sich das eigentlich auf das Erstellen einer DSN-Konfiguration. Andererseits schreibst du im Ausgangsposting 127.0.0.1 als zu kontaktierendes Ziel, was darauf hinauslaufen muss, dass PHP auf der selben Maschine wie das SQL-Express läuft, also Windows. In dem Fall kann beim DSN ein Problem mit dem Scope auftreten (User vs. System) oder dass der Webserver die neue ODBC-Konfiguration aus irgendeinem Grund noch nicht kennt. (So ein (System-)DSN sollte üblicherweise sofort für alle verfügbar sein. Es ist ja keine Umgebungsvariable oder sowas in der Art, das nur einmalig beim Programmstart eingelesen wird.)

        Bei der SQL-Express-Instanz ist auch die Verbindung über TCP/IP freigegeben? Ich glaube, das muss über ein Konfigurationsprogramm extra freigegeben werden. Eigentlich müsste dann auch mit netstat -na ein Lauscher auf 0.0.0.0:1433 zu finden sein (oder eine andere IP-Adresse, nicht nur 127.0.0.1).

        Lo!

        1. Hallo dedlfix,

          Der kleine Tipp mit dem localhost,1433 hat auch nichts gebracht?

          leider nein, hatte ich auch schon gelesen. Ich glaube das war nötig in ältern SQL Server Versionen.

          Wo läuft denn dein PHP? Unix-Maschine? Wenn du von ODBC-Treiber

          Es läuft alles auf einem Win XP Prof System mit Apache 2.2 und PHP 5.2.6

          Bei der SQL-Express-Instanz ist auch die Verbindung über TCP/IP freigegeben?

          ja das wurde bereits gemacht, hatte ich gelesen. Das ist nämlich wie auch NamedPipes standardmäßig abgeschaltet.

          Nun ich forsche mal weiter. Vielleicht muss ich auch meinen Apache nicht als System Account sondern unter einem Admin User laufen lassen?
          hmm. mal sehen.

          vielen Dank und viele Grüße
          hawk

          1. Hi!

            Bei der SQL-Express-Instanz ist auch die Verbindung über TCP/IP freigegeben?
            ja das wurde bereits gemacht, hatte ich gelesen. Das ist nämlich wie auch NamedPipes standardmäßig abgeschaltet.

            Und der netstat zeigt auch was lauschendes an? Mindestens ein Dienst-Neustart ist ja nach solch einer Änderung notwendig.

            Vielleicht muss ich auch meinen Apache nicht als System Account sondern unter einem Admin User laufen lassen?

            Das sollte nicht nötig sein. Ein Versuch mit einem Admin oder auch mal einen normalen User kann aber zumindest nicht schaden.

            Lo!

            1. Hallo

              Und der netstat zeigt auch was lauschendes an? Mindestens ein Dienst-Neustart ist ja nach solch einer Änderung notwendig.

              Ich habe schon zig mal neu gestartet. Auch den Apache habe ich nun mal unter dem gleichen Account laufen lassen.

              Ich suche und lese und google aber ich komme nicht so recht weiter.
              Jetzt habe ich nochmals den neuesten Native Client von MS installiert.

              $MSSQL['HOST'] = 'localhost\SQLEXPRESS';
              $MSSQL['USER'] = 'myAdminName';
              $MSSQL['PWD'] = 'myPassword';
              $MSSQL['DB'] = 'mySQLDB';
              }
              try {
                $DBO = new PDO("odbc:Driver={SQL Server Native Client 10.0};Server={$MSSQL['HOST']};Database={$MSSQL['DB']};Uid={$MSSQL['USER']};Pwd={$MSSQL['PWD']}", $MSSQL['USER'], $MSSQL['PWD']);

              Jetzt kommt die Meldung:
              Error!: SQLSTATE[28000] SQLDriverConnect: 18456 [Microsoft][SQL Server Native Client 10.0][SQL Server]Fehler bei der Anmeldung f�r den Benutzer 'myAdminName'.

              Ich weiss halt nicht so recht was ich hier als Name und Passwort angeben soll. Momentan ist es mein Admin Windows Login Name und Passwort. Der Test Connect mit dem ODBC Treiber ist erfolgreich.

              Wie schön einfach ist es doch mit MySQL :-)

              vielen Dank und viele Grüße
              hawk

  2. Es gibt seit einiger Zeit auch einen SQL Server-Treiber für PHP von Microsoft:
    http://msdn.microsoft.com/en-us/library/ee229551%28v=SQL.10%29.aspx
    In der Beta-Version gibt's endlich auch PDO-Support. Läuft allerdings nur unter Windows ...

    Wäre auf jeden Fall eine bessere Lösung als php_mssql (und PDO_MSSQL), AFAIK wird das nicht mehr weiterentwickelt.

    1. Hallo Patrick,
      vielen Dank für deine Hilfe.
      Du wirst lachen aber in meiner Not habe ich den auch schon ausprobiert.

      Ich bekomme jetzt aber sowohl mit
      new PDO('mssql
      als auch;
      new PDO('odbc

      eine Verbindung hin. Mein Hauptptoblem war glaube ich das ich im SQL Server garnicht diesen User hatte und die Berechtigungen nicht stimmten. Ich dachte das wird mit der Windows Authentifizierng abgedeckt.

      Jetzt habe ich aber diverse andere Probleme wo ich erst mal schauen muss wie ich die beheben kann.
      Es ist ja eine Migration von einer MySQL DB. Diese war komplett in UTF-8

      Jetzt bekomme ich bei MSSQL immer die Meldung:

      Unicode-Daten in einer Nur-Unicode-Sortierung oder ntext-Daten

      Weiss noch nicht woran das liegt.
      Kann MSSQL nicht mit Unicode umgehen?

      Dann habe ich z.b.
      $DBO->query("SELECT @my_key:='SuperNT'");
      das war ja eine MySQL User Variable
      damit kann MSSQL auch nicht umgehen.
      Gibt es sowas auch für MSSQL?

      Fragen über Fragen :-)

      vielen Dank und viele Grüße
      hawk

      1. Hi!

        Mein Hauptptoblem war glaube ich das ich im SQL Server garnicht diesen User hatte und die Berechtigungen nicht stimmten. Ich dachte das wird mit der Windows Authentifizierng abgedeckt.

        Man muss das irgendwie einstellen können, ob der SQL-Server die User selbst verwaltet oder die Windows-Logins nimmt. Zumindest der große kann das hervorragend, beim kleinen weiß ich das grad nicht.

        Kann MSSQL nicht mit Unicode umgehen?

        Es wäre nicht sehr klug, heutzutage noch einen SQL-Server rauszubringen, der nicht mit Unicode und seinen Kodierungsvarianten umgehen kann. Soweit ich weiß, spielt da das N eine große Rolle, sowohl was den Feldtyp angeht (NVARCHAR etc.) als auch bei Stringliteralen. Aber dazu sollte sich doch sicher was brauchbares finden lassen, wenn du deine konkrete Server-Version und das Stichwort Unicode googelst.

        $DBO->query("SELECT @my_key:='SuperNT'");
        das war ja eine MySQL User Variable
        damit kann MSSQL auch nicht umgehen.

        Probier, einfach den Doppelpunkt wegzulassen und ansonsten damit: http://msdn.microsoft.com/de-de/library/ms187953.aspx

        Lo!

        1. Hallo dedlfix,
          nochmals tausend Dank für deine Hilfe.

          Ja das mit dem Prefix N habe ich nun auch schon in vielen Posts gefunden und auch bei MS:
          http://support.microsoft.com/?scid=kb%3Ben-us%3B239530&x=9&y=11

          Es ist wohl so (wenn ich es richtig verstanden habe). Der SQL Server 2008 kann schon mit Unicode umgehen. Es gibt dafür die Typen
          nchar, nvarchar.
          Bei der Migration (ich hatte hier das neueste Migrations Toolkit von MS ausprobiert) wurden diese Spalten auch so umgewandelt.
          Ich habe ja in MySQL alles auf "utf8_general_ci" und noch den Zusatz;
          $DBO->query("SET NAMES 'utf8'");

          Aber das gibt es natürlich bei MSSQL auch nicht.

          Momentan wird nun dieser erste Select angemeckert.

          $result_conf = $DBO->query("SELECT * FROM config");
          $myrowconf = $result_conf->fetch();

          Jetzt weiss ich aber nicht wie man hier den Prefix N unterbringen soll?
          Und dann; ich möchte ja versuchen zweigleisig zu fahren. Also auch weiterhin MySQL zu verwenden wenn gewünscht.
          So aber müsste ich ja alle SQL Befehle anders gestalten.

          Was ich auch nicht ganz verstehe: Wenn ich die Verbindung anstatt mit
          "new PDO('mssql.." mit "new PDO('odbc." mache, dann habe ich dieses Problem bzw. diese Meldung wegen Unicode nicht.

          vielen Dank und viele Grüße
          hawk

          1. Hi!

            Momentan wird nun dieser erste Select angemeckert.
            $result_conf = $DBO->query("SELECT * FROM config");
            Jetzt weiss ich aber nicht wie man hier den Prefix N unterbringen soll?

            Da gar nicht, weil du da ja kein Stringliteral hast.

            Handelt es sich dabei immer noch um diese Meldung:

            Unicode-Daten in einer Nur-Unicode-Sortierung oder ntext-Daten

            Kann es sein, dass du uns hier die Fortsetzung der Meldung unterschlägst, die was von einer Treiberversion erzählt, die mindestens, wenn nicht noch mehr sein muss?

            In dem Fall kann es sein, dass du schlechte Karten hast. Es kann aber auch sein, dass der ODBC-Treiber hier weiterhilft. Wie schon gesagt, habe ich da keine konkreten Erfahrung, und rate hier nur etwas rum, was meine nächsten Schritte in solch einem Fall wären.

            Was ich auch nicht ganz verstehe: Wenn ich die Verbindung anstatt mit
            "new PDO('mssql.." mit "new PDO('odbc." mache, dann habe ich dieses Problem bzw. diese Meldung wegen Unicode nicht.

            Sieh an, also doch ein Treiberversionsproblem. Dann also ODBC.

            Und dann; ich möchte ja versuchen zweigleisig zu fahren. Also auch weiterhin MySQL zu verwenden wenn gewünscht.
            So aber müsste ich ja alle SQL Befehle anders gestalten.

            Das ist das Problem bei einer DBMS-Migration. Es ist nämlich nicht einfach damit getan, eine gleichmachende API wie PDO zu verwenden und den Connection-String zu ändern, um ein anderes DBMS ansprechen zu können. PDO vereinheitlicht nur die Dinge, die das DBMS-Handling angehen, also wie Querys abgesetzt und Ergebnisse geholt werden, etc. Wenn du zur Anwendung hin etwas wirklich austasuchbares haben willst, musst du noch eine Schicht einziehen, die die Anwendung komplett von datenbanktechnischen Dingen abkoppelt. Also einen Datenabstraktionslayer im Gegensatz zu einen Datenbankabstraktionslayer. Du sagst also in der Anwendung nur: "Gib mir Daten" und deine Zwischenschicht formuliert die konkrete Abfrage in Richtung DBMS. Und nun kannst du beim DBMS-Wechsel diese Zwischenschicht anpassen. Der Anwendung ist es nun egal, wo die Daten herkommen, ob nun aus MySQL oder MSSQL. Du kannst auch, vielleicht zu Testzwecken, ein paar Dummy-Daten in einem Array vorhalten.

            Durch die Zwischschicht erhöhst du zwar insgesamt die Komplexität der Anwendung, hast nun aber austauschbare Teile mit definierten Schnittstellen zwischen ihnen.

            Lo!

            1. Hallo dedlfix,

              Sieh an, also doch ein Treiberversionsproblem. Dann also ODBC.

              ja vermutlich.

              Also einen Datenabstraktionslayer im Gegensatz zu einen Datenbankabstraktionslayer. Du sagst also in der Anwendung nur: "Gib mir Daten" und deine Zwischenschicht formuliert die konkrete Abfrage in Richtung DBMS. Und nun kannst du beim DBMS-Wechsel diese Zwischenschicht anpassen. Der Anwendung ist es nun egal, wo die Daten herkommen, ob nun aus MySQL oder MSSQL. Du kannst auch, vielleicht zu Testzwecken, ein paar Dummy-Daten in einem Array vorhalten.

              Ein interessanter Ansatz. Ist mir nur nicht ganz klar wie man sowas umsetzten kann mit dieser "Zwischenschicht". Na ich werde mal schauen ob ich weiterkomme.

              vielen Dank und viele Grüße
              hawk

              1. Hi!

                Ein interessanter Ansatz. Ist mir nur nicht ganz klar wie man sowas umsetzten kann mit dieser "Zwischenschicht". Na ich werde mal schauen ob ich weiterkomme.

                Nun, da ist erst einmal theoretische (Sortier-)Arbeit notwendig. Trenne die Anwendung zwischen der Geschäftslogik und der Datenhaltung. Für alle Daten, die du benötigst oder wegschreiben musst, erstell dir je eine Funktion, die nur die reinen Daten liefert beziehungsweise entgegennimmt. Die können im ersten Schritt Dummy-Daten zurückgeben und übergebene Daten untern Tisch fallen lassen. Dann hast du eine Anwendung, der die Datenhaltung völlig Wurst ist, sie funktioniert auch so. Und du kannst auch ohne alle Datenbankprobleme deine Anwendung entwickeln. Nun ersetzt du die Dummy-Handlungen durch richtige, veränderst aber die Schnittstellen nicht mehr, oder zumindest mit viel Bedacht, denn man ist ja nicht immer fehlerfrei und irrt sich auch mal bei der Schnittstellenerstellung.

                Lo!

              2. Ein interessanter Ansatz. Ist mir nur nicht ganz klar wie man sowas umsetzten kann mit dieser "Zwischenschicht". Na ich werde mal schauen ob ich weiterkomme.

                Du musst das Rad nicht neu erfinden - schau dir Doctrine an. Mit Doctrine schreibst du deine Queries in DQL (wenn du SQL beherrschst, dürfte die Einarbeitungszeit sehr kurz sein). Um die DBMS-Unterschiede (zB LIMIT n bei MySQL vs. TOP n bei MSSQL, ...) kümmert sich dann Doctrine.

                Weiß aber nicht, welche MSSQL-Treiber momentan von Doctrine unterstützt werden. Ich erinnere mich dunkel daran, auf github mal einen Adapter für den sqlsrv-Treiber gefunden zu haben ...

        2. Hallo zusammen,
          hier komme ich nicht recht weiter:
          In MySQL habe ich eine Server Variable so gesetzt.

          $DBO->query("SELECT @my_key:='test-1'");

          Probier, einfach den Doppelpunkt wegzulassen und ansonsten damit: http://msdn.microsoft.com/de-de/library/ms187953.aspx

          wenn ich es beim SQL Server so probiere:
          $DBO->query("SELECT @my_key = 'test-1'");
          oder auch vorher ein Declare setze;

          $DBO->query("DECLARE @my_key As varchar(10)");
          $DBO->query("SELECT @my_key = 'lionht-1'");

          Dann kommt laufend die Meldung:
          Die '@my_key'-Skalarvariable muss deklariert werden.

          Weiss jemand zufällig wie man das in MS SQL macht?

          vielen Dank und viele Grüße
          hawk

          1. Hi!

            $DBO->query("DECLARE @my_key As varchar(10)");
            $DBO->query("SELECT @my_key = 'lionht-1'");

            Dann kommt laufend die Meldung:
            Die '@my_key'-Skalarvariable muss deklariert werden.

            Weiss jemand zufällig wie man das in MS SQL macht?

            Sieht ganz danach aus, als ob die beiden Statements in unterschiedlichen Sessions (oder was auch immer) abgearbeitet werden und die zweite nichts (mehr) von der Deklaration in der ersten weiß. Ich vermute, du wirst das Problem nur mit einer Stored Procedure lösen können (wenn du nicht eine Lösung ganz ohne Variablen findest).

            Lo!

            1. Nochmals Danke dedlfix,

              Ich vermute, du wirst das Problem nur mit einer Stored Procedure lösen können (wenn du nicht eine Lösung ganz ohne Variablen findest).

              ja das glaube ich auch so langsam.
              Vermutlich es weil ich mit dieser Variable auch mit
              AES_ENCRYPT und AES_DECRYPT arbeite und das gibt es ja beim SQL Server auch nicht.

              Muss dann doch vermutlich einiges umsellen, wenn man wirklich zweigleisig fahren will.

              vielen Dank und viele Grüße
              hawk

    2. Hallo Patrick;

      Es gibt seit einiger Zeit auch einen SQL Server-Treiber für PHP von Microsoft:
      http://msdn.microsoft.com/en-us/library/ee229551%28v=SQL.10%29.aspx

      Wenn ich den einbinde bekomme ich laufend die Meldung
      Error!: [08001][Microsoft][SQL Server Native Client 10.0]Named Pipes Provider: Could not open a connection to SQL Server [2].

      ich bekomme es einfach nicht hin, obwohl alle Protokolle aktiv sind im SQL Server.

      vielen Dank und viele Grüße
      hawk