删除的字符使用WinHttpReadData从简单的php服务中检索文件

时间:2016-06-11 17:11:27

标签: php c++ xml winapi webserver

我在IIS Web服务器上设置了一个简单的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;
}

?>

我在C ++中使用WinHttp的WinHttpReadData检索文件。

编辑#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计算机通过Internet访问服务时,它也可以正常工作。但是,当我在通过互联网访问的Windows 10计算机上运行客户端时,我会删除字符。有趣的是,它是每次从XML文件中删除的特定字符集。 (其他,二进制,文件也会受到影响,但我还没有确定它们有什么变化。)

如果XML文件包含以“<Style”开头的元素,则该文本将消失。所以,这个:

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

成为这个:

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

请注意,样式元素的开头被切掉了。这是唯一受影响的元素,如果文件中有多个元素,它似乎只影响第一个元素。

令我困惑的是为什么从Windows 7运行客户端不会发生这种情况。

编辑:其他一些文件(二进制和文本)每个缺少1到3个字符。似乎只在文件中发生一次丢弃。文件的其余内容与源代码相同。

2 个答案:

答案 0 :(得分:0)

我无法理解上述阅读程序,它也是不完整的。请保持简单,如下例所示。

您遇到二进制文件问题时,建议您不要以二进制模式打开输出tempFile

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
readfile('whatever.bin');
?>

答案 1 :(得分:0)

我似乎解决了这个问题。我的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;
}

现在,文件下载没有任何损坏。为什么我在这种情况下需要这样的标题是超出我的。系统的哪个部分在响应消息最终进入缓冲区之前搞乱了?我不知道。