У меня есть простая служба php, настроенная на веб-сервере IIS. Он используется моим клиентом для получения файлов с сервера. Это выглядит так:
<?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 ++.
РЕДАКТИРОВАТЬ № 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>
становится так:
<Element1>blah blah</Element1>
_Element>hoopa hoopa</Style_Element>
<Element2>bip bop bam</Element2>
Обратите внимание, что начало элемента стиля обрезано. Это единственный затронутый элемент, и, похоже, он влияет на первый, только если в файле более одного элемента.
Что меня озадачивает, так это то, почему этого не происходит при запуске клиента из Windows 7.
РЕДАКТИРОВАТЬ: Некоторые другие файлы, двоичные и текстовые, не содержат от 1 до 3 символов каждый. Кажется, что падение происходит только один раз в файле. Остальное содержимое файла идентично исходному.
Я не могу понять смысл вышеприведенной процедуры чтения, она также неполная. Просто сделайте это просто, как в примере ниже.
Тот факт, что у вас проблемы с бинарными файлами, говорит о том, что вы не открываете вывод 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');
?>
Кажется, я решил проблему. Мой 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;
}
Теперь файлы загружаются без каких-либо повреждений. Зачем мне нужен такой заголовок в этой ситуации мне не подходит. Какая часть системы работает с ответным сообщением, прежде чем оно попадет в мой буфер? Я не знаю.