per PHP auf Navison Datenbank zugreifen? (CC)

14. Januar 2014 12:49

Hallo zusammen,

ich weiß nicht wirklich ob mir hier jemand helfen kann, dies ist ja kein php Forum, aber hier sind soviele kluge Köpfe...

Unser neustes Projekt ist die Einfühung eines "Intranet" in unserer Firma, wo neben Daten aus der Prozessleittechnik usw. auch Daten von NAV
angezeigt werden sollen. Also z.B. Grafische Anzeigen des Lagerbestandes und ähnliches.
Also habe ich mich etwas in die Materie von "HTML" , "CSS" , "Javascript" und "Php" eingearbeitet - wobei ich sicherlich noch nicht viel kann.

Mein erster Ansatz die Daten in die "webpage" zu bekommen war exportieren via ".csv" oder ".xml" oder ähnliches - das muss ja aber zyklisch z.B.
per "Projektwarteschlange" oder ählichem geschehen.

Nun gibt es wohl auch die Möglichkeit direkt auf SQL-Tabellen zuzugreifen - ich finde nur derzeit noch keinen gangbaren Weg.

Mein erster Lösunsgansatz (der natürlich nicht funktioniert):
Code:
<?php
 $path = realpath("/\\srv-nav\DATA/TEST_11_2013_Data.mdf");
 $defaultDir = dirname($path);
 $connectionString =
 'Driver={Microsoft Navision Driver};'.
 'DriverId=790;'.
 'Dbq='.$path.';'.
 'DefaultDir='.$defaultDir.';';

 echo $connectionString;

 $conn = mssql_connect($connectionString,"user","passwort") or die("Fehler");

 $sql2 = "SELECT * FROM Name";

 $result2 = odbc_exec($conn, $sql2);

 if (odbc_fetch_row($result2, 1)) {
    echo odbc_result($result2, "Name");
 }
 odbc_close($conn);
?>


Wahrscheinlich bin ich total auf den Holzweg? Kann jemand helfen?

Re: per PHP auf Navison Datenbank zugreifen? (CC)

14. Januar 2014 14:19

Trenn es. Mach keinen direkten Zugriff auf den SQL-Server, sondern nutze Webservices. In PHP nutzt Du entweder die eingebauten SOAP-Funktionen oder Du nutzt NuSOAP (wir machen das, weil man da von der PHP-Version weniger abhängig ist). Andereseits die Frage, warum eine zusätzliche Technologie, wenn IIS und ASP.NET quasi schon vorhanden sind.

Re: per PHP auf Navison Datenbank zugreifen? (CC)

14. Januar 2014 14:21

Hab noch vergessen, wenn Du auf die SQL-DB direkt willst, dann such mal nach "PHP PDO", da gibt es die Möglichkeit den SQL-Server diret anzusprechen. Aber das muss der PDO-DB-Treiber in PHP einkompiliert sein, sonst ist nicht.

Volker

Re: per PHP auf Navison Datenbank zugreifen? (CC)

14. Januar 2014 14:39

Hallo Volker,
erst einmal vielen Dank für die schnelle Antwort.

An Webservices habe ich auch schon gedacht aber da habe ich noch weniger Ideen wie ich das anfangen soll - und IIS und ASP.NET kenn ich
auch nooch garnicht...

Re: per PHP auf Navison Datenbank zugreifen? (CC)

14. Januar 2014 15:36

So schwer ist das nicht. Unten mal ein einfaches Stück Code zum Zugriff af einen Webservice aus NAV, mit Prüfung ob Online und Logging in eine errorlog-Datei.

Nichts desto trotz würde ich mir mal ASP.NET ansehen, schließlich kann man da genauso in C# bzw. VB wiefür NAV nun auch programmieren. Darüber hinaus gibt es da schon fertiges, wie DotNetNuke als Portal-Lösung, oder Du nimmst gleich die Sharepointservices und entwickelst dafür. Warum ich so auf ASP.NET rumreite? Wegen der einfacheren Implementierung der notwendigen Rechte. Oder dürfen am Ende alle alles in eurem Intranet?

Code:
function WriteLog_dbnavsend($errormessage){
   $fp=fopen('errorlog.txt','a');
   fwrite($fp,$errormessage);
   fwrite($fp,"\r\n");
fclose($fp);}

include_once('../includes/configure.php');

require_once(DIR_FS_DOCUMENT_ROOT.'/services/nusoap/lib/nusoap.php'); //$_SERVER['DOCUMENT_ROOT']
WriteLog_dbnavsend(DIR_FS_DOCUMENT_ROOT.'/services/nusoap/lib/nusoap.php');


function NotifyNAV($xtcorderid, $webshopname, $webshopcode){

   $navwsurl="ws.domain.de";
   $success=0;
   if (CheckNAVServerOnline($navwsurl)==1){
         $soap = new nusoap_client("http://ws.domain.de/myConnect/GetOrderFromXTC.asmx?WSDL", true);
         $params =array('xtcOrderID' => $xtcorderid, 'WebShopName' => $webshopname, 'WebShopSecurityCode' => $webshopcode);
         $result = $soap->call("NewOrder", array('parameters' => $params));
      WriteLog_dbnavsend("call done");
         if(is_array($result)){
               foreach($result as $answer){
                  $success = $answer;
               }
         }
         else {
            $success=$result;}
   }
   return $success;
}

function CheckNAVServerOnline($navwebserver, $navport=80){
   $online=0;
   $fp = fsockopen($navwebserver, $navport, $errno, $errstr, 3);
   if (!$fp) {
      WriteLog_dbnavsend("offline");
      $online=0;
   } else {
      $online=1;
      WriteLog_dbnavsend("online");
      fclose($fp);
   }
   return $online;
}

Re: per PHP auf Navison Datenbank zugreifen? (CC)

14. Januar 2014 15:53

Hier ein generischer OOP Ansatz der keine Zusatzbibliotheken braucht

Code:
<?php

define('USERPWD', 'intern\expandit:password');

class Webservice {
      
   private $baseURL = 'http://entwicklung.intern.mydomain:7047/DynamicsNAV/WS/';   
   private $client = null;
   
   public function __construct() {
      // we unregister the current HTTP wrapper
      stream_wrapper_unregister('http');
      // we register the new HTTP wrapper
      stream_wrapper_register('http', 'NTLMStream') or die("Failed to register protocol");          
   }      
   
   private function dumpError($faultcode, $faultstring) {
         echo "Error:<br />" . nl2br($faultcode) . '<br /><br />Error Details:<br />'. nl2br($faultstring) . '<br />';         
         echo("<br />REQUESTHEADERS :<br />" . htmlspecialchars($this->client->__getLastRequestHeaders()) . "<br />");
         echo("<br />REQUEST :<br />" . htmlspecialchars($this->client->__getLastRequest()) . "<br />");
         echo("<br />RESPONSEHEADERS:<br />" .htmlspecialchars($this->client->__getLastResponseHeaders()) . "<br />");
         echo("<br />RESPONSE:<br />" .htmlspecialchars($this->client->__getLastResponse()) . "<br />");
   }
   
   public function __Action($action, $uri, &$paramsAsArray) {
      //var_dump(&$paramsAsArray);
      $this->client = @new NTLMSoapClient($this->baseURL.$uri);               
      try {                            
         $result = $this->client->$action(&$paramsAsArray);                                 
         return $result;         
      } catch (SoapFault $vException) {
         $this->dumpError($vException->faultcode,$vException->faultstring);                        
      }         
   }
   
   public function ListCompanies() {
      $this->client = @new NTLMSoapClient($this->baseURL.'SystemService');               
      try {         
         // Find the first Company in the Companies
         $result = $this->client->Companies();
         $companies = $result->return_value;
         return $companies;                    
      } catch (SoapFault $vException) {
         $this->dumpError($vException->faultcode,$vException->faultstring);                        
      }         
   }

} //end of class


/* dont touch anything below */

class NTLMSoapClient extends SoapClient {
 
    function __doRequest($request, $location, $action, $version) {
        $headers = array(
            'Method: POST',
            'Connection: Keep-Alive',
            'User-Agent: PHP-SOAP-CURL',
            'Content-Type: text/xml; charset=utf-8',
            'SOAPAction: "'.$action.'"',
        );
       
        $this->__last_request_headers = $headers;
       
        $ch = curl_init($location);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_POST, true );
        curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
        curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
        curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
        curl_setopt($ch, CURLOPT_USERPWD, USERPWD);
        $response = curl_exec($ch);
        return $response;
    }

    function __getLastRequestHeaders() {
        return implode("\n", $this->__last_request_headers)."\n";
    }
}


class NTLMStream
{
    private $path;
    private $mode;
    private $options;
    private $opened_path;
    private $buffer;
    private $pos;
    /**
     * Open the stream
      *
     * @param unknown_type $path
     * @param unknown_type $mode
     * @param unknown_type $options
     * @param unknown_type $opened_path
     * @return unknown
     */
    public function stream_open($path, $mode, $options, $opened_path) {
        $this->path = $path;
        $this->mode = $mode;
        $this->options = $options;
        $this->opened_path = $opened_path;
        $this->createBuffer($path);
        return true;
    }
    /**
     * Close the stream
     *
     */
    public function stream_close() {
        curl_close($this->ch);
    }
    /**
     * Read the stream
     *
     * @param int $count number of bytes to read
     * @return content from pos to count
     */
    public function stream_read($count) {
        if(strlen($this->buffer) == 0) {
            return false;
        }
        $read = substr($this->buffer,$this->pos, $count);
        $this->pos += $count;
        return $read;
    }
    /**
     * write the stream
     *
     * @param int $count number of bytes to read
     * @return content from pos to count
     */
    public function stream_write($data) {
        if(strlen($this->buffer) == 0) {
            return false;
        }
        return true;
    }
    /**
     *
     * @return true if eof else false
     */
    public function stream_eof() {
        return ($this->pos > strlen($this->buffer));
    }
    /**
     * @return int the position of the current read pointer
     */
    public function stream_tell() {
        return $this->pos;
    }
    /**
     * Flush stream data
     */
    public function stream_flush() {
        $this->buffer = null;
        $this->pos = null;
    }
    /**
     * Stat the file, return only the size of the buffer
     *
     * @return array stat information
     */
    public function stream_stat() {
        $this->createBuffer($this->path);
        $stat = array(
            'size' => strlen($this->buffer),
        );
        return $stat;
    }
    /**
     * Stat the url, return only the size of the buffer
     *
     * @return array stat information
     */
    public function url_stat($path, $flags) {
        $this->createBuffer($path);
        $stat = array(
            'size' => strlen($this->buffer),
        );
        return $stat;
    }
    /**
     * Create the buffer by requesting the url through cURL
     *
     * @param unknown_type $path
     */
    private function createBuffer($path) {
        if($this->buffer) {
            return;
        }
        $this->ch = curl_init($path);
        curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($this->ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
        curl_setopt($this->ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
        curl_setopt($this->ch, CURLOPT_USERPWD, USERPWD);
        $this->buffer = curl_exec($this->ch);
        $this->pos = 0;
    }
}

?>



Und dann in deinem PHP Controller zB auf eine Webservice - PAge zugreifen
Code:
...   
   public function __construct($what) {
                ...
[b]      $this->webservice = new Webservice();[/b]
...


Code:
             
               $categories = default_Model::getCategories();                                       
                $speakers = array();
                $speakerObj = $this->webservice->__Action('ReadMultiple', '88%20Aufzugswerke%20M.Schmitt+Sohn/Page/Trainers', $paramsAsArray);   
            if (is_array($speakerObj->ReadMultiple_Result->Trainers)) {
               foreach($speakerObj->ReadMultiple_Result->Trainers as $obj) {
                  $speakers[] = get_object_vars($obj);
               }
            } else {
               $speakers[] = get_object_vars($courseObj->ReadMultiple_Result->Trainers);
            }               
            if ($this->debug) var_dump($speakers);                                  



Aber wenn ich die Wahl hätte würde ich das Intranet auch in ASP gestalten :-P :evil:

Re: per PHP auf Navison Datenbank zugreifen? (CC)

14. Januar 2014 16:04

PS: MSSQL über PHP klappt so bei mir

Code:
$server = 'ENTWICKLUNG';

// Mit MSSQL verbinden
$verbindung = mssql_connect($server, 'sa', 'passwort');

if (!$verbindung) {
    die('Beim Aufbau der Verbindung mit MSSQL ging etwas schief');
}
   
mssql_select_db('Cronus_60_DE');

$res = mssql_query('SELECT * FROM [dbo].Company');

while ($datensatz = mssql_fetch_array($res)) {
   print_r($datensatz);
}

Re: per PHP auf Navison Datenbank zugreifen? (CC)

14. Januar 2014 16:26

@JoergR

wenn ich das aber richtig sehe, dann läuft Deine ganze Webanwendung aber unter einem User mit den dazugehörigen Rechten. Und "sa" ist ja nicht wenig. oder habe ich d was überlesen?

Re: per PHP auf Navison Datenbank zugreifen? (CC)

14. Januar 2014 16:30

Das PHP Skript authentifiziert sich am Webservice mit einem Service Account an (hier ein Domänenaccount). Dies ist abhängig davon wie der Webservice Dienst konfiguriert ist. Wir benötigen eine NTLM Anmeldung.

In dem Beispiel wo die Verbindung direkt zum SQL Server aufgebaut wird, wird einfachhalber der SA verwendet. Das kann ein beliebiger SQL User sein, der entsprechende Berechtigungen auf die Datenbank hat...

gruß

Re: per PHP auf Navison Datenbank zugreifen? (CC)

14. Januar 2014 16:42

dann brauchs Du aber eine eigene Rechteverwaltung in Deiner Webanwendung und kannst nicht auf die Rechte in NAV zurückgreifen. Geht halt mit ASP.NET doch einfacher.

Re: per PHP auf Navison Datenbank zugreifen? (CC)

14. Januar 2014 16:54

Da wir keine Windows-Benutzer in NAV verwenden ist es anders nicht möglich. Andernfalls kann man mit dem Internet Explorer den angemeldeten Windows-User über Kerberos / SPNEGO an den Webservice durchreichen und benötigt dann keinen dedizierten Serviceaccount.
Ohne separate Rechteverwaltung stelle ich mir ein PHP basiertes Intranet etwas schwierig vor...und deshalb tendiere ich hier klar zu Sharepoint :-P

Re: per PHP auf Navison Datenbank zugreifen? (CC)

15. Januar 2014 11:20

Hallo nochmal,

nach langem Testen und googln - ich komm leider wieder nicht weiter...

Ich denke der Jörg ist schon auf den richtigen Weg gekommen - ich würde wegen der Benutzerrechte
einen extra Datenbank-Benutzer anlegen mit beschänkten Rechten.
Ich möchte ja auch ersteinmal nichts schreiben sondern nur etwas auslesen...
(ASP - schaue ich mir aber auch sicherlich noch an.)

Der Weg von Jörg ist leider veraltet und wird wohl bei ab PHP5 oder so nicht mehr untertützt...
Ich habe mir deshalb - nach den Anleitungen im Netz die "neuen" .dll's eingespielt.

Mein neuer Code sieht nun so aus:
Code:
<?php
    $server = 'srv-nav\navison';

    $connectionInfo = array( "Database"=>"TEST_11_2013", "UID"=>"user", "PWD"=>"passwort");

    // Mit MSSQL verbinden
    $verbindung = sqlsrv_connect($server,$connectionInfo);

    if ($verbindung) {
        die('Beim Aufbau der Verbindung mit MSSQL ging etwas schief');
    }

    //mssql_select_db('TEST_11_2013');
    $sql ='SELECT * FROM [dbo].Company';
    $params = array(1,"somedata");
    //$res = sqlsrv_query($verbindung,$sql,$params);

    $stmt = sqlsrv_query($sql,$params);
    if( $stmt === false ) {
     die( print_r( sqlsrv_errors(), true));
}

    if( $res === false ) {
     die( print_r( sqlsrv_errors(), true));

}
    while ($datensatz = sqlsrv_fetch_array($res,SQLSRV_FETCH_ASSOC)) {
       print_r($datensatz);
    }
?>


Ist immer noch Quatsch :-) ich verstehe auch ncoh nicht sio ganz was ich da mache....

Er scheint aber eine Verbindung aufzubauen ... bekomme dann aber Meldungen wie:
"Warning: sqlsrv_query() expects parameter 1 to be resource, string given in C:\xampp\htdocs\SQL_TEST\sql3.php on line 18
Array ( [0] => Array ( [0] => IMSSP [SQLSTATE] => IMSSP [1] => -14 [code] => -14 [2] => An invalid parameter was passed to sqlsrv_query. [message] => An invalid parameter was passed to sqlsrv_query. ) )"

Komm hier nicht weiter...

Re: per PHP auf Navison Datenbank zugreifen? (CC)

15. Januar 2014 12:55

Hi,

ich kenn den Ablauf nict genau, aber Du führst wohl eine Abfrage ( $stmt = sqlsrv_query($sql,$params);) aus, aber auf welcher Serververbindung?

Ich vermute mal das "//$res = sqlsrv_query($verbindung,$sql,$params);" auskommentiert gehört, evtl. sogar gekürzt auf "$res = sqlsrv_query($verbindung,$sql);".

Das
Code:
  $stmt = sqlsrv_query($sql,$params);
    if( $stmt === false ) {
     die( print_r( sqlsrv_errors(), true));
}
ist in meinen Auge doppelt im Code und sinnlos.

Aber
Ich möchte ja auch ersteinmal nichts schreiben sondern nur etwas auslesen...

Wenn Du dann mal was nach NAV schreiben willst, fängst Du wieder eine neue Entwicklung an? Du wllst doch hoffentlich nicht direkt in die NAV-DB schreiben.

Re: per PHP auf Navison Datenbank zugreifen? (CC)

16. Januar 2014 08:21

Wenn Du dann mal was nach NAV schreiben willst, fängst Du wieder eine neue Entwicklung an? Du wllst doch hoffentlich nicht direkt in die NAV-DB schreiben


Natürlich nicht - ich denke ich würde das über xml-Dateien machen oder so ähnlich - diese dann einlesen damit auch die Trigger durchlaufen werden und Prüfungen der Daten gemacht werden können.

Gruß Matthias

Re: per PHP auf Navison Datenbank zugreifen? (CC)

16. Januar 2014 11:11

Nein das machst du dann eher über Webservices :-P ... genau dafür sind die bestens geeignet (NAV Geschäftslogik und Funktionalität für externe Applikationen bereitstellen).

PS: Anscheinend benutzt du Windows mit PHP ...denn nur für den Windows-Port ist die mssql-Extension seit 5.3 deprecated.

gruß