2016-06-11 6 views
0

IIS Webサーバーに簡単なPHPサービスが設定されています。クライアントからサーバーにファイルを取得するために使用されます。WinHttpReadDataを使用して単純なPHPサービスからファイルを取得する際に文字がドロップされる

<?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; 
} 

?> 

私はWinHttpのWinHttpReadDataをC++で取得しています。

EDIT#2:ここはC++コードです。これは私のプログラムにどうやって登場するか正確には分かりません。私は複数のクラスから作品を取り上げなければなりませんでしたが、要点は明らかです。

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()); 
} 

Windows 7またはWindows 10マシンのいずれかのサーバーコンピュータ名を使用してローカルネットワーク経由で何千ものファイルをテストすると、すべて正常に動作します。また、Windows 7マシンからインターネット経由でサービスにアクセスするとうまく動作します。しかし、インターネットを介してアクセスするWindows 10マシンでクライアントを実行すると、文字がドロップされます。興味深いのは、それがXMLファイルから毎回削除される特定の文字セットであるということです。 (他のバイナリファイルも同様に影響を受けますが、まだ変更内容を確認していません)

XMLファイルに "<Style"で始まる要素が含まれていると、そのテキストは消えます。だから、この:

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

はこれを次のようになります。style要素の始まりは切り落とされ

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

ていることに注意してください。これは影響を受ける唯一の要素であり、ファイルに複数の要素がある場合、最初の要素にのみ影響するようです。 、他のバイナリファイル、およびテキストのいくつかの1〜3文字のそれぞれから欠落している:私をperplexes何

が、これはWindows 7の

EDITからクライアントを実行している起こらない理由です。ドロップはファイル内で一度しか起こらないようです。ファイルの残りの内容は、ソースと同じです。

+0

C++側のコードも表示します。 –

答えて

0

私は上記の読書ルーチンを理解できません、それはまた不完全です。下の例のように単純にしておきます。

バイナリファイルで問題が発生しているという事実は、出力tempFileをバイナリモードで開いていないことを示しています。私は問題を解決し

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

ご協力ありがとうございます。あなたの要求に含まれている読み込みルーチンは完全ではありません。私が編集で言ったように、それはさまざまなクラスに散らばっているビットからすぐに一緒にスローされるコードです。しかし、それは問題ではありません。また、出力ファイルもありません。 WinHttpReadDataを呼び出した直後に、文字の欠落の問題がバッファに表示されます。データが書き出される前に、データが破損しています。私がphpでreadfileを使用しなかったのは、大きなファイルでメモリに問題があるかもしれないという記事を読んだからです。記事は私がしたように断片でそれを送ることを提案した。 –

+0

@ Barmak Shemirani - ここでは、PHPで大きなファイルのダウンロードを処理する方法について説明した記事です。セクション4. [リンク](http://www.media-division.com/the-right-way-to-handle-file-downloads-in-php)readfiileまたはfpassthruを使用すると全く同じ問題が発生します。 –

+0

私はそのリンクを理解していません。 'readfile'ドキュメントはそれに対して特に反対しています。また、あなたのクライアントコードはPHPの 'header'を見ていません。 –

0

、それはそうです:次のように

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); 
} 

あなたのPHPファイルを簡略化することができます。私のPHPサービスはヘッダー情報を含んでいませんでした(私はそれが必要と思っていませんでした)ので、私はコンテンツタイプapplication/octet-streamのヘッダー仕様を追加して、更新されたサービスは次のようになりました。

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; 
} 

ここでファイルは破損することなくダウンロードされます。このような状況でこのようなヘッダーが必要なのはなぜ私が超えているかです。システムのどの部分が応答メッセージを私のバッファーに蓄積する前に乱していますか?知りません。

関連する問題