U
U
Undressmyfuture2020-08-18 20:14:03
PHP
Undressmyfuture, 2020-08-18 20:14:03

How to organize file exchange between PHP server and C# desktop application?

Hello. I am developing my first client-server application, and there is a task to download files from the server and upload them back. I know that the easiest way is WebClient , but my task is more complicated - the files themselves must be stored secretly, and certain logic must be performed on the server side (issue this or that file, or even refuse, etc.).
I see the algorithm like this:

  • In c# I send a get request to a php script on the server
  • PHP receives a request, refuses and returns an error, or finds the required file and returns it with a byte array
  • In C# I get a response, I read the stream through streamreader, I save the file

Am I completely delusional, or is this how it should happen?
Php and syasharp know a little, webrequests too , but then somehow not. I don’t even know which side to approach, if you google - only examples with downloading through the browser fall out, not that. I'm sure I'm still missing the nuances - encryption? checksum check? etc.
I understand that the question is lengthy, but just a kick in the right direction is enough for me. The answer in the style of "go read about http sockets" is fine too :)

Answer the question

In order to leave comments, you need to log in

2 answer(s)
V
Vladimir Korotenko, 2020-08-18
@firedragon

Receiving files and storing them are 2 completely unrelated tasks,
Sending a php file
https://habr.com/ru/post/151795/
receiving a file

WebRequest request = WebRequest.Create("http://somesite.com/private/myfile.txt");
            WebResponse response = request.GetResponse();
            using (Stream stream = response.GetResponseStream())            
            using (StreamReader reader = new StreamReader(stream))
                {
                    string line = "";
                    while ((line = reader.ReadLine()) != null)
                    {
                        Console.WriteLine(line);
                    }                     
            }
            response.Close();

U
Undressmyfuture, 2020-08-25
@Undressmyfuture

I'll leave here what I picked up, maybe it will come in handy for someone (so far only for downloading the file):

  • It is better to send a request from a C# application through the HttpWebRequest class , it returns an HttpWebResponse , which has more useful things available;
  • The most commonly used request method is POST ;
  • Sending php files by a script is universal for downloading both by the browser and by the c# application;
  • Returning files can be done in many ways, the simplest is the php function readfile($pathToFile);
  • simultaneously with the return of files, the php script can return the so-called headers - one might say, "accompanying documentation" to the answer. For example, if you execute the line header("HTTP/1.1 403 Forbidden"); then the C# GetResponse() function will return the appropriate Exception. You can also specify the file name in headers:
    header('Content-Disposition: attachment; filename=' . basename($filepath));
  • For adequate downloading by the browser, you need to register several headers, see the php documentation ;
  • In a C# application, you can get headers through the HttpWebResponse.Headers property;
  • The file arrives as a stream of bytes, and there are many ways to save it as a file. I liked the way through FileStream the most.

Well, actually a little Hindu code:
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();
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question