• Как организовать обмен файлами между PHP сервером и C# десктоп приложением?

    @Undressmyfuture Автор вопроса
    Оставлю здесь то, что наковырял, может кому пригодится (пока только по скачиванию файла):
    • Отправлять запрос из C# приложения лучше через класс HttpWebRequest, он возвращает HttpWebResponse, у которого доступно больше полезных штук;
    • Чаще всего используется метод запроса POST;
    • Отдача файлов php скриптом универсальна для скачивания как браузером, так и c# приложением;
    • Отдачу файлов можно сделать разными способами, самый простой - функция php readfile($pathToFile);
    • одновременно с отдачей файлов php-скрипт может отдавать так называемые headers - можно сказать, "сопроводительную документацию" к ответу. Например, если выполнить строку header("HTTP/1.1 403 Forbidden"); то функция C# GetResponse() вернет соответствующий Exception. Еще в headers можно прописать имя файла:
      header('Content-Disposition: attachment; filename=' . basename($filepath));
    • Для адекватного скачивания браузером нужно прописать несколько headers, посмотреть в документации по php;
    • В C# приложении получить headers можно через свойство HttpWebResponse.Headers;
    • Файл приходит как поток байтов, и сохранить его как файл можно разными способами. Мне больше всего приглянулся способ через FileStream.


    Ну и собственно немного индусского кода:
    C#:
    using System.Net;
    using System.IO;
    ///returns: путь к файлу при успешном скачивании, иначе текст ошибки
    public static string DownloadDistr()
    {
        string folder = "C:\downloads";
    	//формирую строку запроса
        string data = "email=" + userEmail + "&" + "password=" + userPassword;
        HttpWebRequest request = HttpWebRequest.CreateHttp("http://yoursite.com/downloadfile.php");
        request.Method = "POST";
        byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(data);
        request.ContentType = "application/x-www-form-urlencoded";
        request.ContentLength = byteArray.Length;
    
        //отправляю web запрос
        try
        {
            using (Stream dataStream = request.GetRequestStream())
            {
                dataStream.Write(byteArray, 0, byteArray.Length);
            }
        }
        catch (Exception ex)
        {
            return "Error: " + ex.Message;
        }
    
        //получаю ответ
        try
        {
            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
            {
                if (response.StatusCode != HttpStatusCode.OK)
                {
                    return response.StatusCode.ToString();
                }
                //получаю из headers имя файла
                WebHeaderCollection headers = response.Headers;
                //вот тут как-то тупо, но и так сойдет
                string checkFilename = headers["Content-Disposition"].Split('=').Last(); 
                string pathToSave = Path.Combine(folder, checkFilename);
    
                //сохраняю файл через байт-буфер и FileStream
                byte[] buffer = new byte[1024];
                int read;
                using (FileStream download = new FileStream(pathToSave, FileMode.Create))
                {
                    using (Stream stream = response.GetResponseStream())
                    {
                        while ((read = stream.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            download.Write(buffer, 0, read);
                        }
                    }
                }
                return pathToSave;
            }
        }
        catch (Exception ex)
        {
            return "Error: " + ex.Message;
        }
    }


    PHP:
    <?php
    $userEmail = "unknownid";
    $userPassword = "unknownPass";
    //получаю данные из запроса
    if (isset($_POST['email']) && isset($_POST['password'])) {
        $userEmail = strip_tags($_POST['email']);
        $userPassword = strip_tags($_POST['password']);
    }  else {
        echo ('Error request');
        return;
    }
    //каким-то образом проверяю данные, могу запретить скачивание
    if($userEmail != "correctEmail" || $userPassword != "correctpassword") {
        header("HTTP/1.1 403 Forbidden");
        return;
    }
    //путь к отдаваемому файлу
    $filepath = "download/file.zip";
    if (!file_exists($filepath)) {
        header("HTTP/1.1 404 Not Found");
        return;
    }
    try {
    	//на всякий случай очищаю буфер вывода
        if (ob_get_level()) {
            ob_end_clean();
        }
    	//header из которого получу имя файла
        header('Content-Disposition: attachment; filename=' . basename($filepath));
    	
    	//а эти headers нужны в первую очередь для браузера, оставил на всякий случай
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Transfer-Encoding: binary');
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');
        header('Content-Length: ' . filesize($filepath));+
    	//отдаю файл
        readfile($filepath);
        exit;
    } catch (Exception $ex) {
        echo $ex->getMessage();
    }
    Ответ написан
    Комментировать