CGI upload/download files

General FreeBASIC programming questions.
JohanD
Posts: 11
Joined: Dec 23, 2014 7:06

CGI upload/download files

Postby JohanD » Dec 23, 2014 16:47

Hi,

I have successfully managed to read forms, and create CGI's under Ubuntu with Freebasic, and with code found on this forum.
Now, I like to be able to recieve and send binary files, like a PFD file.
How do I implement that ? A bit of a noob question I guess..
I guess the code below will not do it ...


[code=text file=Untitled.bas] ...
Dim as String strPost = ReadStdin()
file = Post(strPost,"file")
...[/code]


Current code:

[code=text file=Untitled.bas]

Function URLDecode(arg as string) as string
Dim as string char, query, value, rlt
Dim i as integer
char = "&H"
For i = 0 To len(arg)
query = Mid(arg, i, 1)
If query = "%" Then
value = chr(valint(char & Mid(arg, i + 1, 2)))
rlt = rlt & value
i = i + 2
ElseIf query = "+" Then
value = " "
rlt = rlt & value
Else
rlt = rlt & query
End If
Next
URLDecode = rlt
End Function

Function SplitVar(query as string, arg as string) as string
Dim as string value, rlt
If InStr(query, arg) <> 0 Then
value = Mid(query, InStr(query, arg), len(query))
If Instr(value, "&") <> 0 Then
rlt = Mid(value, len(arg) + 2, Instr(value, "&") - len(arg) - 2)
Else
rlt = Mid(value, len(arg) + 2, len(value))
End If
Else
rlt = ""
End If
SplitVar = URLDecode(rlt)
End Function

Function ReadStdin() as string
Dim numChars as integer
Dim postQuery as string
numChars = val(environ("CONTENT_LENGTH"))
open cons for input as #1
postQuery = space(numChars)
get #1,,postQuery
close #1
ReadStdin = postQuery
End Function

Function QueryString(arg as string) as string
If environ("REQUEST_METHOD") = "GET" Then
QueryString = SplitVar(environ("QUERY_STRING"), arg)
Else
QueryString = ""
End If
End Function

Function Post(query as string, arg as string) as string
If environ("REQUEST_METHOD") = "POST" Then
Post = SplitVar(query, arg)
Else
Post = ""
End If
End Function
[/code]
Julcar
Posts: 89
Joined: Oct 19, 2010 18:52
Contact:

Re: CGI upload/download files

Postby Julcar » Dec 28, 2014 8:48

Hi, you may be want to read about binary functions, because the common html form for file upload send binary data back to server, and in that case you cannot treat it as string but as binary.
JohanD
Posts: 11
Joined: Dec 23, 2014 7:06

Re: CGI upload/download files

Postby JohanD » Dec 28, 2014 9:02

I was thinking like that.
Suppose I have a form, where one can select a file for upload, and an email address..
How to get both in FB puzzles me.
The form:

[code=html4strict file=Untitled.bas]<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>File Upload</title>
</head>
<body>
<form action="/cgi-bin/upload.cgi" method="post"
enctype="multipart/form-data">
<p>Photo to Upload: <input type="file" name="photo" /></p>
<p>Your Email Address: <input type="text" name="email_address" /></p>
<p><input type="submit" name="Submit" value="Submit Form" /></p>
</form>
</body>
</html>[/code]

So I need to get the file into a binary variable ? but also the email address as in the sample.
Thats where I am stuck.
JohanD
Posts: 11
Joined: Dec 23, 2014 7:06

Re: CGI upload/download files

Postby JohanD » Dec 28, 2014 17:01

I have solved it by using a Perl script and a hidden field.
Would like to see a genuine FB solution, if there is any.
Its above my head..
Julcar
Posts: 89
Joined: Oct 19, 2010 18:52
Contact:

Re: CGI upload/download files

Postby Julcar » Apr 17, 2015 7:12

Well, as web programmer, I don't like mix binary and text data on the same form, because that would be making complex your life, more easy and reliable is treat both data in distinct ways, and making an exclusive form for web uploading, which you can process with and only with binary functions.
Julcar
Posts: 89
Joined: Oct 19, 2010 18:52
Contact:

Re: CGI upload/download files

Postby Julcar » Jun 30, 2019 19:37

Just to point, the "native" solution for file uploading is as follows:

Code: Select all

#lang "fb"
#include "crt.bi"

Sub GetStdinData(StdinContent As String)
  Dim As Integer Length = Val(Environ("CONTENT_LENGTH"))
  Dim As String Block = Space(Length)
  Dim Content As String
  Dim ReadLen As Integer
  _setmode(_fileno(stdin), _O_BINARY)
  ReadLen = Fread(@Block[0], 1, Length, stdin)
  For i As Integer = 0 To ReadLen - 1
    Content &= Chr(Block[i])
  Next
  StdinContent = Content
End Sub

Function MultiPost(StdinQuery As String, FieldName As String, FileName As String = "", FileType As String = "", FilePath As String = "") As String
  'This function retrieves form fields passed through a multipart/form-data form
  'if the function detects a file being uploaded it just returns its filename and
  'internally saves the file using the three optional paremeters to set the filename
  'and the file type.
  Dim As String Boundary, ContDisp, ContType, FileExt, StrData, BinData
  'Custom cursors
  Dim As Integer BoundaryPos, BeginPos, EndPos, StartPos
  BoundaryPos = 1
  BeginPos = 1
  'Get the boundary
  Boundary = Mid(StdinQuery, BoundaryPos, InStr(BoundaryPos, StdinQuery, Chr(10)))
  Do While BoundaryPos > 0
    'Get the "Content-Disposition" header
    BeginPos = InStr(BoundaryPos, StdinQuery, "Content-Disposition:")
    EndPos = InStr(BeginPos, StdinQuery, Chr(10))
    ContDisp = Mid(StdinQuery, BeginPos, EndPos - BeginPos)
    'Get the field name
    BeginPos = InStr(ContDisp, "name=") + 6
    EndPos = InStr(BeginPos, ContDisp, Chr(34))
    If FieldName = Mid(ContDisp, BeginPos, EndPos - BeginPos) Then
      'Look if we have the filename field
      BeginPos = InStr(ContDisp, "filename=")
      If BeginPos > 0 Then
        'Get the file name
        BeginPos = BeginPos + 10
        EndPos = InStr(BeginPos, ContDisp, Chr(34))
        If FileName = "" Then
          'No file name passed to call, use the original file name
          FileName = Mid(ContDisp, BeginPos, EndPos - BeginPos)
        End If
        If FileName <> "" Then
          'Uploading a file
          BeginPos = InStr(BoundaryPos, StdinQuery, "Content-Type:") + 14
          EndPos = InStr(BeginPos, StdinQuery, CHR(10))
          'Get the Content-Type header
          ContType = Mid(StdinQuery, BeginPos, EndPos - BeginPos)
          'Verify if content-type match
          If InStr(ContType, FileType) <> 0 Then
            'Now get the extension based on the Content-Type header
            FileExt = Mid(ContType, InStr(ContType, CHR(47)) + 1)
            'Remove trailing line feed
            FileExt = Left(FileExt, Len(FileExt) - 1)
            'Add the extension to file name
            FileName = FileName + Chr(46) + FileExt
          Else
            FileName = ""
          End If
          'Now start with the binary data
          StartPos = InStr(BeginPos, StdinQuery, ContType) + Len(ContType) + 3
          BinData = Mid(StdinQuery, StartPos, InStr(StartPos, StdinQuery, Boundary) - (StartPos + 2))
          'Save the file on disk
          Dim As Integer fFile = FreeFile
          Open FilePath + FileName For Binary Access Write As #fFile
          Put #fFile, 1, BinData
          Close #fFile
          'Clean memory
          BinData = ""
          StrData = FileName
        End If
      Else
        BeginPos = InStr(BoundaryPos, StdinQuery, "Content-Disposition:") + Len(ContDisp) + 3
        EndPos = InStr(BeginPos, StdinQuery, Chr(10)) - 1
        StrData = Mid(StdinQuery, BeginPos, EndPos - BeginPos)
      End If
      Exit Do
    End If
    BoundaryPos = InStr(BoundaryPos + Len(Boundary), StdinQuery, Boundary)
  Loop
  MultiPost = StrData
End Function

Sub UploadFile()
  If Environ("REQUEST_METHOD") = "POST" Then
    If InStr(Environ("CONTENT_TYPE"), "multipart/form-data") > 0 Then
      Dim As String StdinContent, FileName, FileType, FileUploaded, StrPost, Referrer
      GetStdinData(StdinContent)
      'Get headers
      FileName = LCase(MultiPost(StdinContent, "file-name"))
      StrPost = "&file-name=" + FileName
      FileType = MultiPost(StdinContent, "file-type")
      FileUploaded = MultiPost(StdinContent, "file-content", FileName, FileType, "root/uploads")
      Referrer = Environ("HTTP_REFERER")
      If InStr(Referrer, Chr(63)) = 0 Then
        Referrer = Referrer + Chr(63)
      End if
      If FileUploaded <> "" Then
        StrPost = StrPost + "&file-uploaded=" + FileUploaded
        Print "Location: " + Referrer + StrPost + Chr(13,10)
      Else
        Print "Location: " + Referrer + StrPost + "&upload=failed" + Chr(13,10)
      End If
    End If
  End If
End Sub


The functions were deployed to be adapted to my project, but should be easy to adapt to some other scenarios.
bcohio2001
Posts: 556
Joined: Mar 10, 2007 15:44
Location: Ohio, USA
Contact:

Re: CGI upload/download files

Postby bcohio2001 » Jun 30, 2019 22:47

@Julcar

It seems that we both have a "web browser".
Would like to see your source code. Mine at the moment is Windows only, but am trying to multi-platform.
Julcar
Posts: 89
Joined: Oct 19, 2010 18:52
Contact:

Re: CGI upload/download files

Postby Julcar » Jul 01, 2019 7:46

bcohio2001 wrote:@Julcar

It seems that we both have a "web browser".
Would like to see your source code. Mine at the moment is Windows only, but am trying to multi-platform.


My project isn't a web browser, instead it is a content management system, similar to drupal or joomla

Return to “General”

Who is online

Users browsing this forum: No registered users and 7 guests