2016-06-11 18 views
0

Ich habe einen einfachen php Service, der auf einem IIS Web-Server eingerichtet wird. Es wird von meinem Client verwendet, um Dateien vom Server abzurufen. Es sieht wie folgt aus:Zeichen, die fallen gelassen werden, die Dateien vom einfachen php Service mit WinHttpReadData zurückholen

<?php 

if (isset($_GET['file'])) 
{ 
    $filepath = "C:\\files\\" . $_GET['file']; 

    if (!strpos(pathinfo($filepath, PATHINFO_DIRNAME), "..") && file_exists($filepath) && !is_dir($filepath)) 
    { 
     set_time_limit(0); 
     $fp = @fopen($filepath, "rb"); 

     while(!feof($fp)) 
     { 
      print(@fread($fp, 1024*8)); 
      ob_flush(); 
      flush(); 
     } 
    } 
    else 
    { 
     echo "ERROR at www.testserver.com\r\n"; 
    } 

    exit; 
} 

?> 

ich die Dateien mit WinHttp des WinHttpReadData in C++ abrufen.

EDIT # 2: Hier ist der C++ - Code. Dies ist nicht genau so, wie es in meinem Programm erscheint. Ich musste Stücke aus mehreren Klassen ziehen, aber der Kern sollte offensichtlich sein.

session = WinHttpOpen(appName.c_str(), WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); 

if (session) connection = WinHttpConnect(session, hostName.c_str(), INTERNET_DEFAULT_HTTP_PORT, 0); 

if (connection) request = WinHttpOpenRequest(connection, NULL, requestString.c_str(), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0); 

bool results = false; 

if (request) 
{ 
    results = (WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0) != FALSE); 
} 

if (results) 
{ 
    results = (WinHttpReceiveResponse(request, NULL) != FALSE); 
} 

DWORD bytesCopied = 0; 
DWORD size = 0; 

if (results) 
{ 
    do { 
     results = (WinHttpQueryDataAvailable(request, &size) != FALSE); 

     if (results) 
     { 
      // More available data? 
      if (size > 0) 
      { 
       // Read the Data. 
       size = min(bufferSize, size); 

       ZeroMemory(buffer, size); 

       results = (WinHttpReadData(request, (LPVOID)buffer, size, &bytesCopied) != FALSE); 
      } 
     } 

     if (bytesCopied > 0 && !SharedShutDown.GetValue()) 
     { 
      tempFile.write((PCHAR)RequestBuffer, bytesCopied); 

      if (tempFile.fail()) 
      { 
       tempFile.close(); 
       return false; 
      } 

      fileBytes += bytesCopied; 
     } 
    } while (bytesCopied > 0 && !SharedShutDown.GetValue()); 
} 

Alles funktioniert gut, wenn ich (Tausende von Dateien) testen über das lokale Netzwerk auf den Server-Computername entweder von einem Windows 7 oder Windows 10-Maschine. Es funktioniert auch gut, wenn ich über ein Windows 7-Gerät auf den Dienst über das Internet zugreife. Wenn ich den Client jedoch auf einem Windows 10-Computer ausführen lasse, der über das Internet zugreift, werden die Zeichen gelöscht. Das Interessante daran ist, dass es sich um eine bestimmte Menge von Zeichen handelt, die jedes Mal aus XML-Dateien gelöscht werden. (Andere binäre Dateien sind ebenfalls betroffen, aber ich habe noch nicht bestimmt, welche Änderungen an ihnen vorgenommen wurden.)

Wenn die XML-Datei ein Element enthält, das mit "<Style" beginnt, verschwindet dieser Text. Also, das:

<Element1>blah blah</Element1> 
<Style_Element>hoopa hoopa</Style_Element> 
<Element2>bip bop bam</Element2> 

wird dies:

<Element1>blah blah</Element1> 
_Element>hoopa hoopa</Style_Element> 
<Element2>bip bop bam</Element2> 

Beachten Sie, dass der Anfang des Stilelements abgehackt wird. Dies ist das einzige betroffene Element, und es scheint nur das erste Element zu betreffen, wenn mehr als eins in der Datei vorhanden ist.

Was mich verwirrt ist, warum dies nicht der Fall den Client von Windows ausgeführt 7.

EDIT: einige der anderen Dateien, Binär-und Text, sind von 1 bis 3 Zeichen je fehlt. Es scheint, dass ein Drop nur einmal in einer Datei passiert. Der Rest des Inhalts der Datei ist identisch mit der Quelle.

+0

Zeigen Sie den Code für C++ Seite auch. –

Antwort

0

Ich kann die obige Lese-Routine nicht sinnvoll machen, sie ist auch unvollständig. Behalte es einfach wie im folgenden Beispiel.

Die Tatsache, dass Sie Probleme mit Binärdateien haben, legt nahe, dass Sie die Ausgabe tempFile nicht im Binärmodus öffnen.

std::ofstream tempFile(filename, std::ios::binary); 

while(WinHttpQueryDataAvailable(request, &size) && size) 
{ 
    std::string buf(size, 0); 
    WinHttpReadData(request, &buf[0], size, &bytesCopied); 
    tempFile.write(buf.data(), bytesCopied); 
} 

Ihre PHP-Datei kann wie folgt vereinfacht werden:

<?php 
readfile('whatever.bin'); 
?> 
+0

Danke für Ihre Hilfe.Die Leseprozedur, die ich auf Ihre Anfrage hin eintrage, ist nicht vollständig. Wie ich in meinem Edit gesagt habe, handelt es sich um Code, der schnell aus Bits zusammengesetzt wird, die in verschiedenen Klassen verteilt sind. Aber das ist nicht das Problem. Noch ist die Ausgabedatei. Das Problem mit fehlenden Zeichen wird unmittelbar nach dem Aufruf von WinHttpReadData im Puffer angezeigt. Die Daten sind beschädigt, bevor sie ausgeschrieben werden. Der Grund, warum ich readfile in php nicht benutzt habe, war, weil ich einen Artikel gelesen habe, der besagt, dass es Speicherprobleme mit großen Dateien haben könnte. Der Artikel schlug vor, es in Stücke zu schicken, wie ich es getan habe. –

+0

@ Barmak Sheimerani - Hier ist der Artikel, der über die Handhabung großer Dateidownloads in PHP gesprochen hat. Abschnitt 4. [Link] (http://www.media-division.com/the-right-way-to-handle-file-downloads-in-php) Mit readfiile oder fpassthru produzieren genau das gleiche Problem. –

+0

Ich verstehe diesen Link nicht. Die "readfile" -Dokumentation spricht ausdrücklich dagegen. Auch Ihr Client-Code schaut nicht auf PHP 'header'. –

0

ich das Problem gelöst, wie es scheint. Mein PHP-Dienst enthielt keine Header-Informationen (dachte nicht, dass ich sie brauchte), also dachte ich, ich würde versuchen, eine Header-Spezifikation für den Inhaltstyp application/octet-stream hinzuzufügen, nur um zu sehen, was sich ergeben würde. Mein aktualisierter Service sah so aus:

if (isset($_GET['file'])) 
{ 
    $filepath = "C:\\Program Files (Unrestricted)\\Sony Online Entertainment\\Everquest Yarko Client\\" . $_GET['file']; 

    if (!strpos(pathinfo($filepath, PATHINFO_DIRNAME), "..") && file_exists($filepath) && !is_dir($filepath)) 
    { 
     header("Content-Type:application/octet-stream"); 

     set_time_limit(0); 
     $fp = @fopen($filepath, "rb"); 

     while(!feof($fp)) 
     { 
      print(@fread($fp, 1024*8)); 
      ob_flush(); 
      flush(); 
     } 
    } 
    else 
    { 
     echo "ERROR at www.lewiefitz.com\r\n"; 
    } 

    exit; 
} 

Jetzt können die Dateien ohne Korruption heruntergeladen werden. Warum ich in dieser Situation einen solchen Header brauche, ist mir ein Rätsel. Welcher Teil des Systems wird mit der Antwortnachricht durcheinander gebracht, bevor sie in meinem Puffer gelandet ist? Ich weiß es nicht.