German Dateien mit Poststring uploaden

Matzele73

Member
Licensed User
Longtime User
Hallo Zusammen,
leider muss ich euch nochmal mit diesem Thema belästigen und meinen Thread http://www.b4x.com/android/forum/threads/poststring.35549/ erneut aufgreifen, da ich mich damals wohl mißverständlich ausdgedrückt habe (ich möchte keine eMail verschicken ) und das Problem weiterhin nicht gelöst ist.

Also:
Wir entwickeln momentan eine speziellen Client für behinderte Personen. Der Client sammelt über eine spezielle Oberfläche einen Text, ein Bild und eine Sound-Datei und legt diese in ein leeres Verzeichnis auf dem Gerät.Mit Hilfe eines Posts sollen die Dateien auf einen Server upgeloadet werden. Eine PHP-Funktion, die auf dem Server liegt verwandelt diese drei Dateien in eine eMail und versendet diese an den Empfänger, der ebenfalls an den Server gepostet wird.

Nun mein Problem:
Ich weiss leider nicht, wie ich den Poststring formartieren soll und wie ich ihn konkret an den Server posten kann.

Die PHP-Funktion, die mein mittlerweile verstorbener Kollege auf dem Server hinterlegt hat, wurde wie folgt von ihm dokumentiert:
sendqumail.php

Hierüber werden die Nachrichten versendet. Per POST unter der Kennung „upload1“ (upload1 bis 4) werden maximal 4 Dateien an das Script geschickt:

hallo.txt
Darin steht der Nachrichtentext.

data.txt
Diese Datei beinhaltet die nötigen Angaben zum Versand:

qubMode=sp
to=Mailadresse des Empfängers
sms=Mobilfunknummer des Empfängers
subject=Nachricht


Zusätzlich kann noch eine Bilddatei im JPG-Format und eine Audiodatei an das Script übermittelt werden.

und sieht so aus:
B4X:
<?PHP
include("login.php");

$query = 'SELECT Id FROM maildata WHERE Id = "'.mysql_escape_string($uid).'"';
$result = mysql_query($query);
if (mysql_num_rows($result) == 1) {
    //Put this php upload script in your apache php webserver.
    //Set the url to this script in your vb upload client
    $dirname = $uid."-".time();
    if (!file_exists($tmppath.$dirname)) {
      mkdir($tmppath.$dirname);
      chmod($tmppath.$dirname, 0777);
    }
    $tmplocation = $tmppath.$dirname;
    $max_size = 10000000; //File upload size
    $filelist = "";

    $mailtext = print_r($_FILES, true);
    $fmailname = "swtest.txt";
    $out = fopen($fmailname,"w+");
    fwrite($out, $mailtext);
    fclose($out);
 
    $x = 0;
    //This loop here will save ur file to the server
    for ($num = 1; $num < count($_FILES)+1; $num++){

        $event = "Success";
 
        // Check if upload for field is required
        if (! $_FILES['upload'.$num]['name'] == ""){
            if ($_FILES['upload'.$num]['name'] == "data.txt" || $_FILES['upload'.$num]['name'] == "hallo.txt" || strtolower(substr($_FILES['upload'.$num]['name'],-3)) == "jpg" || strtolower(substr($_FILES['upload'.$num]['name'],-3)) == "wav" || strtolower(substr($_FILES['upload'.$num]['name'],-3)) == "m4a" || strtolower(substr($_FILES['upload'.$num]['name'],-3)) == "mp3") {
              if ($_FILES['upload'.$num]['size'] < $max_size) {     
                move_uploaded_file($_FILES['upload'.$num]['tmp_name'],$tmplocation."/".$_FILES['upload'.$num]['name']) or $event = "Failure";
/*
                if (strtolower(substr($_FILES['upload'.$num]['name'],-3)) == "m4a") {
                    $ftaskname = $shelltaskpath.$uid."_".time()."_".$_FILES['upload'.$num]['name']."_ffmpeg.sh";
                    $taskcontent = '#!/bin/bash'."\n";
                    $audiofname = $tmplocation."/".$_FILES['upload'.$num]['name'];
                    $fmp3name = str_replace("m4a","mp3",$audiofname);
                    $taskcontent .= $ffmpegpath." -i ".$audiofname."  -ab 128000 -map_meta_data 0:0 ".$fmp3name;
                    $out = fopen($ftaskname,"w+");
                    fwrite($out, $taskcontent);
                    fclose($out);
                    chmod($ftaskname, 0777);
                                                               
                    $xy=0;
                 
                    while (!file_exists($fmp3name) && $xy < 5) {
                        $xy = $xy + 1;
                        sleep(5);
                    }
                 
                        if (file_exists($fmp3name)) $filename = $fmp3name;
                        else $filename = $tmplocation."/".$_FILES['upload'.$num]['name'];
                } else {
                        $filename = $tmplocation."/".$_FILES['upload'.$num]['name'];
                }
*/
                $filename = $tmplocation."/".$_FILES['upload'.$num]['name'];
                if ($x == 0) $filelist = $filename;
                else $filelist .= ",".$filename;
                $x = 1;
              } else {
                $event = "File too large!";
              }
              /* print("Uploading File $num $event\r\n"); */
        }
        }
      }
   
      if (file_exists($tmplocation."/data.txt") && file_exists($tmplocation."/hallo.txt")) {
              include_once($rootpath.'pclzip.lib.php');
            $archive = new PclZip($tmplocation.".zip");
            $v_list = $archive->create($filelist,PCLZIP_OPT_REMOVE_ALL_PATH);
         
            if (file_exists($tmplocation.".zip")) {
                copy($tmplocation.".zip", $mailoutpath.$dirname.".zip");
                unlink($tmplocation.".zip");
                include_once($rootpath.'recrmdir.php');
                rec_rmdir($tmplocation);
             
                if (file_exists($mailoutpath.$dirname.".zip")) {
                    header("Location: https://www.qubal.net/momo/qubalsend.php?file=".$dirname.".zip");
                }
            }
    }
}

?>

Ein weiterer Kollege, der aber für mich leider auch nicht mehr greifbar ist, hat die zusammenstellung des zu übermittelnden String in einer C++-Funktion so zusammengestellt:
B4X:
'    sSendString = "--Xu02=$" & CRLF & _
'"Content-Disposition: form-data; name=""upload1""; filename=""data.txt""" & CRLF & _
'"Content-Type: File" & CRLF & CRLF & _
'"pw=" & CRLF & _
'"To=muster@testserver.de" & CRLF & _
'"Sms=" & CRLF & _
'"subject=Nachricht" & CRLF & _
'"qubMode=sp" & CRLF & CRLF & _
'"--Xu02=$" & CRLF & _
'"Content-Disposition: form-data; name=""upload2""; filename=""hallo.txt""" & CRLF & _
'"Content-Type: File" & CRLF & CRLF & _
'sMsg & CRLF & _
'"--Xu02=$--" & CRLF
'PostString(

Folgender Versuch von mir führt leider nicht zum gewünschten Erfolg:
B4X:
Sub SendQubalMessage() As Boolean

    Dim sSendString As String
    Dim sMsg As String = "Test"    'SetQubalMsg_Text

    sSendString = "--Xu02=$" & CRLF & _
        "Content-Disposition: form-data; name=""upload1""; filename=""data.txt""" & CRLF & _
        "Content-Type: File"      & CRLF & CRLF & _
        "pw=" & UserPW      & CRLF & _
        "to=" & mailadress  & CRLF & _
        "Sms="                    & CRLF & _
        "subject=qubal Nachricht" & CRLF & _
        "qubalMode=sp"            & CRLF & CRLF & _
        "--Xu02=$"                & CRLF & _
        "Content-Disposition: form-data; name=""upload2""; filename=""hallo.txt""" & CRLF & _
        "Content-Type: File"      & CRLF & CRLF & _
        sMsg                      & CRLF & _
        "--Xu02=$--"              & CRLF
       
    Dim Job1 As HttpJob
    Job1.Initialize("Job1", Main)
    Job1.Username = Main.qUserName
    Job1.Password = Main.qUserPW
    Job1.PostString(ServerPath & CmdSendMessage, sSendString)

    Return True

Über Eure Hilfe würde ich mich SEHR freuen!

Viele Grüße
Matthias
 

DonManfred

Expert
Licensed User
Longtime User
In meiner Signatur ist ein funktionierendes Beispiel inkl php-Datei die in dem Beispiel verwendet wird
 

Matzele73

Member
Licensed User
Longtime User
Wow, das ist super!
Vielen Dank!

Hast du mir noch eine Idee, wie ich Benutzername und Passwort in diesem Fall an den Server übergeben kann?

Viele Grüße
Matthias
 

DonManfred

Expert
Licensed User
Longtime User
Wenn du die Prüfung auf usernamen und passwort in der php-Datei übernimmst dann kannst du sie doch einfach in dem Post mitsenden...

B4X:
    Dim NV As Map
    NV.Initialize
    NV.Put("username", "HansMuster")
    NV.Put("passwort", "123456")
    NV.Put("action", "upload")

Wenn username und/oder passwort nicht oder falsch übergeben werden dann akzeptierst du den Upload einfach nicht.

Ich persönlich würde den Zugriffsschutz lieber über php als über eine .htaccess-Datei regeln.
du könntest aber auch mit der Phone-lib die DeviceID ermitteln und diese zusammen mit der subscriberID als Authentifizierung nutzen. Setzt natürlich vorraus das alle die die App benutzen dürfen in deiner Datenbank vorhanden sind.

Möglichkeiten hat man schon ein paar.
 
Last edited:

Knoppi

Active Member
Licensed User
Longtime User
Hallo Matthias,

der Code von DonManfred ist schon richtig gut und Du solltest ihn auch verwenden.

Dennoch müßte Dein Code auch funktionieren wenn Du CRLF durch CHR(13)&CHR(10)ersetzt.
CRLF ist in B4A nur ein CHR(10).

viele Grüße
Knoppi
 

DonManfred

Expert
Licensed User
Longtime User
Dennoch müßte Dein Code auch funktionieren wenn Du CRLF durch CHR(13)&CHR(10)ersetzt.
CRLF ist in B4A nur ein CHR(10).

Ja, in dem Multipartpost.bas von erel ist das auch so umgesetzt...

B4X:
Dim EOL As String
    EOL = Chr(13) & Chr(10) 'CRLF constant matches Android end of line character which is chr(10).

Und in dem Multipartpost-code wird dann immer EOL anstelle von CRLF verwendet.
 

Matzele73

Member
Licensed User
Longtime User
hallo knoppi, hallo don manfred,
vielen dank für eure bisherige unterstützung. leider gelingt mir nach wie vor die authentifizierung am server nicht. ich habe jetzt folgenden code zum senden:
B4X:
Sub SendQubalMessage() As Boolean
  hc.Initialize("hc")

    'Add files
    If File.Exists(File.DirDefaultExternal & "/preparemail","data.txt") Then
        Dim files As List
        files.Initialize
        Dim fd As FileData
        fd.Initialize
        fd.Dir = File.DirDefaultExternal & "/preparemail"
        fd.FileName = "data.txt"
        fd.KeyName = "upload1"
        fd.ContentType = "application/octet-stream"
        files.Add(fd)
    End If
  
    'Add second file
    If File.Exists(File.DirDefaultExternal & "/preparemail","hallo.txt") Then
        Dim fd As FileData
        fd.Initialize
        fd.Dir = File.DirDefaultExternal & "/preparemail"
        fd.FileName = "hallo.txt"
        fd.KeyName = "upload2"
        fd.ContentType = "application/octet-stream"
        files.Add(fd)
    End If
  
    'If File.Exists(File.DirDefaultExternal & "/preparemail","qubalPicture.jpg") Then
    'If File.Exists(File.DirDefaultExternal & "/preparemail","qubalRec.wav") Then

Dim sf As StringFunctions

    'Add name / values pairs (parameters)
        Dim NV As Map
        NV.Initialize
'        NV.Put("note1", "abc")
'        NV.Put("note2", "def")
        NV.Put("User", Main.qUserName)
        NV.Put("Password", sf.Encrypt(Main.qUserPW))
        NV.Put("action", "upload")
      
    Dim req As HttpRequest
        req = MultipartPost.CreatePostRequest(ServerPath & CmdSendMessage, NV, files)
        hc.Execute(req, 1)
End Sub

die verschiedenen variationen der parameter wie "user", "User", "Username", "password", "Passwort", etc. habe ich alle durch. auch das verschlüsseln des passwortes habe ich mittlerweile eingebaut.
leider ohne erfolg. :-(

die funktion CreatePostRequest sieht bei mir so aus:
B4X:
Sub CreatePostRequest(URL As String, NameValues As Map, Files As List) As HttpRequest
   Dim boundary As String
   boundary = "--Xu02=$"     '"---------------------------1461124740692"
   Dim stream As OutputStream
   stream.InitializeToBytesArray(20)
   Dim EOL As String
   EOL = Chr(13) & Chr(10) 'CRLF constant matches Android end of line character which is chr(10).
   Dim b() As Byte
   If NameValues <> Null AND NameValues.IsInitialized Then
     'Write the name/value pairs
     Dim key, value As String
     For i = 0 To NameValues.Size - 1
       key = NameValues.GetKeyAt(i)
       value = NameValues.GetValueAt(i)
       b = ("--" & boundary & EOL & "Content-Disposition: form-data; name=" _
         & QUOTE & key & QUOTE & EOL & EOL & value & EOL).GetBytes("UTF8")
       stream.WriteBytes(b, 0, b.Length)
     Next
   End If
   If Files <> Null AND Files.IsInitialized Then
     'write the files
     Dim FD As FileData
     For i = 0 To Files.Size - 1
       FD = Files.Get(i)
       b = ("--" & boundary & EOL & "Content-Disposition: form-data; name=" _
         & QUOTE & FD.KeyName & QUOTE & "; filename=" & QUOTE & FD.FileName & QUOTE _
         & EOL & "Content-Type: "  & FD.ContentType & EOL & EOL).GetBytes("UTF8")
       stream.WriteBytes(b, 0, b.Length)
       Dim In As InputStream
       In = File.OpenInput(FD.Dir, FD.FileName)
       File.Copy2(In, stream) 'read the file and write it to the stream
       b = EOL.GetBytes("UTF8")
       stream.WriteBytes(b, 0, b.Length)
     Next
   End If
'   b = (EOL & "--" & boundary & "--" & EOL).GetBytes("UTF8")
   b = (EOL & boundary & "--" & EOL).GetBytes("UTF8")
   stream.WriteBytes(b, 0, b.Length)
   b = stream.ToBytesArray
   'msgbox(b.Length, "")
   Dim request As HttpRequest
   request.InitializePost2(URL, b)
   request.SetContentType("multipart/form-data; boundary=" & boundary)
   request.SetContentEncoding("UTF8")
   Return request
End Sub

was hat dieses "boundary" auf sich?

viele grüße
matthias
 

DonManfred

Expert
Licensed User
Longtime User
Hast du den Ordner mittels einer .htaccess-Datei geschützt?
Wenn ja, dann wirst du mit den Daten
B4X:
NV.Put("User", Main.qUserName)
NV.Put("Password", sf.Encrypt(Main.qUserPW))

nichts anfangen können weil diese Infos ja gar nicht in der PHP-Datei ankommen. Das war ja genau meine aussage oben...

"Wenn du die Prüfung auf usernamen und passwort in der php-Datei übernimmst dann kannst du sie doch einfach in dem Post mitsenden..."

Wenn du dir meine PHP-Datei anguckst (die in dem verlinkten Thread) dann wirst du feststellen, das diese eine LOG-Datei schreibt. DA findest Du alle Infos die an der PHP-Datei ankommen... Da stünde dann auch besagter username oder das verschlüsselte Passwort in der LOG-Datei.

Desweiteren schrieb ich:

Wenn username und/oder passwort nicht oder falsch übergeben werden dann akzeptierst du den Upload einfach nicht.

Ich persönlich würde den Zugriffsschutz lieber über php als über eine .htaccess-Datei regeln.
du könntest aber auch mit der Phone-lib die DeviceID ermitteln und diese zusammen mit der subscriberID als Authentifizierung nutzen. Setzt natürlich vorraus das alle die die App benutzen dürfen in deiner Datenbank vorhanden sind.


Boundary:
siehe z.b. hier oder hier oder hier.
 
Last edited:

DonManfred

Expert
Licensed User
Longtime User
btw: Du solltest abends mal hier in den thread gucken. Dann könnte man vieles schneller erklären/abklären. Abends habe ich am meisten Zeit hier ins forum zu gucken und zu schreiben. Tagsüber arbeite ich. ;)

PS: Wenn Du explizit irgendwo hilfe brauchst dann musst du kontreter werden. Wir können nicht erraten was falsch läuft bzw nicht so recht klappt.
 
Last edited:

Matzele73

Member
Licensed User
Longtime User
hallo donmanfred,
danke für deine geduld.

leider kann ich abends nicht posten, da ich nur tagsüber im büro bin. von zuhause habe ich nicht alles im zugriff, vorallem nicht die hardware.

der zugriffschutz wird auf unserem server mittels php geregelt. alle user, die eine zugriffsberechtigung auf das system haben, sind in einer MySQL-datenbank hinterlegt.

die "login.php"- datei sieht wie folgt aus:
PHP:
<?PHP
include("/home/httpd/qubal/momo/config.php");
include($rootpath."db_connect.php");

if (!isset($_SERVER['PHP_AUTH_USER'])) {
    header('WWW-Authenticate: Basic realm="My Realm"');
    header('HTTP/1.0 401 Unauthorized');
    exit;
} else {
    $query = 'SELECT Id FROM maildata WHERE Alias = "'.mysql_escape_string($_SERVER["PHP_AUTH_USER"]).'" AND Web_PW = "'.mysql_escape_string($_SERVER["PHP_AUTH_PW"]).'" OR Alias = "'.mysql_escape_string($_SERVER["PHP_AUTH_USER"]).'" AND Web_PW = "'.md5(mysql_escape_string($_SERVER["PHP_AUTH_PW"])).'" OR "chipauth" = "'.mysql_escape_string($_SERVER["PHP_AUTH_USER"]).'" AND RFID = "'.md5(mysql_escape_string($_SERVER["PHP_AUTH_PW"])).'"';
    $result = mysql_query($query);
    if (mysql_num_rows($result) < 1) {
        header('WWW-Authenticate: Basic realm="My Realm"');
        header('HTTP/1.0 401 Unauthorized');
        exit;
    } else {
        while ($row = mysql_fetch_assoc($result)) {
            $uid = $row["Id"];
        }
    }
}
?>

mit hilfe einer log-funktion habe ich nun definitiv feststellen können, dass die authentifizierung beim posten der dateien scheitert.

meine aktuelle sende-funktion sieht mittlerweile so aus:
B4X:
Sub SendQubalMessage() As Boolean
 
    'Add files
    If File.Exists(File.DirDefaultExternal & "/preparemail","data.txt") Then
        Dim files As List
        files.Initialize
        Dim fd As FileData
        fd.Initialize
        fd.Dir = File.DirDefaultExternal & "/preparemail"
        fd.FileName = "data.txt"
        fd.KeyName = "upload1"
        fd.ContentType = "application/octet-stream"
        files.Add(fd)
    End If
   
    'Add second file
    If File.Exists(File.DirDefaultExternal & "/preparemail","hallo.txt") Then
        Dim fd As FileData
        fd.Initialize
        fd.Dir = File.DirDefaultExternal & "/preparemail"
        fd.FileName = "hallo.txt"
        fd.KeyName = "upload2"
        fd.ContentType = "application/octet-stream"
        files.Add(fd)
    End If
   
    'If File.Exists(File.DirDefaultExternal & "/preparemail","qubalPicture.jpg") Then
    'If File.Exists(File.DirDefaultExternal & "/preparemail","qubalRec.wav") Then

Dim sf As StringFunctions

    'Add name / values pairs (parameters)
        Dim NV As Map
        NV.Initialize
        NV.Put("upload1", "data.txt")
        NV.Put("upload2", "hallo.txt")

'        NV.Put("username", Main.qUserName)
'        NV.Put("passwort", sf.Encrypt(Main.qUserPW))
'
'        NV.Put("action", "upload")
       
      hc2.Initialize("hc2")
    Dim req As HttpRequest
   
'        hc2.ExecuteCredentials(req, 111, Main.qUserName, sf.Encrypt(Main.qUserPW))
        req = MultipartPost.CreatePostRequest(ServerPath & "sendqubalmail_log.php", NV, files)        'CmdSendMessage
        hc2.Execute(req, 111)

'        req2.InitializeGet(ServerPath & CmdSendMessage)
        hc2.ExecuteCredentials(req, 111, Main.qUserName, sf.Encrypt(Main.qUserPW))

Return True
End Sub

beim empfangen von dateien konnte ich es so lösen:
B4X:
Sub SendHTTPqubalRequest(reqNr As Int, Cmd As String)

    Dim HC As HttpClient
    Dim req2 As HttpRequest

    HC.Initialize("hc")
   
    req2.InitializeGet(qubal.ServerPath & Cmd)
    HC.ExecuteCredentials(req2, reqNr, qUserName, qUserPW)

End Sub

viele grüße
matthias
 

DonManfred

Expert
Licensed User
Longtime User
bin grad auf arbeit. nicht viel zeit.
nur so viel

PHP:
if (!isset($_SERVER['PHP_AUTH_USER'])) {
    header('WWW-Authenticate: Basic realm="My Realm"');
    header('HTTP/1.0 401 Unauthorized');
    exit;

Hier kommt dein aufruf nicht vorbei... $_SERVER['PHP_AUTH_USER'] ist nicht gefüllt an dieser Stelle.

Ich schau´s mir nachher mal ob ich helfen kann wenn ich zu hause bin...
 

DonManfred

Expert
Licensed User
Longtime User
Hast du es mal einfach SO probiert?
B4X:
hc2.ExecuteCredentials(req, 111, Main.qUserName, sf.Encrypt(Main.qUserPW))

also ohne die Zeile

B4X:
 hc2.Execute(req, 111)

vorher auszuführen? Das sollte SO doch eigentlich funktionieren. Beim download hast du es doch auch so gelöst
 

Matzele73

Member
Licensed User
Longtime User
Jetzt funktioniert es! :D
Vielen, vielen Dank für deine Geduld und Unterstützung! :)

Viele Grüße
Matthias
 
Top