home *** CD-ROM | disk | FTP | other *** search
/ CD Shareware Magazine 1999 April / CD_Shareware_Magazine_31.iso / Free / Prg / upload_cgi.exe / Upload_CGI.bas next >
Encoding:
BASIC Source File  |  1997-03-11  |  24.5 KB  |  719 lines

  1. Attribute VB_Name = "vb32_CGI"
  2. '------------ VB4_Upload_CGI (32 Bit) ------------
  3. '
  4. ' This program has been tested with Netscape Enterprise Server for NT.
  5. '
  6. ' Written by Kent Empie (kempie@chesco.com, kempie@usa.net, http://www.chesco.com/~kempie)
  7. '
  8. ' Special thanks to:
  9. '   Paul Stohr (http://www.prplus.com) for his tips on using the Win32API
  10. '   to communicate with standard in/out as well as a couple of the CGI subs.
  11. '
  12. '   Premier Solutions Ltd. (http://www.premierltd.com) for allowing me to
  13. '   publish code that was partially developed while under their employment.
  14. '
  15. ' Note: Sub Main() is the "startup form" for this program.
  16. '----------------------------------------------------------------------
  17.  
  18. Option Explicit
  19.  
  20. Global Const csUploadDir = "http_uploads"
  21. Global gsOutputFileName As String
  22. Global gsOutputFilePath As String
  23. Global glOutputFileLen As Long
  24.  
  25. 'Declare the needed Win32 API functions
  26. Declare Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As Long) As Long
  27. Declare Function GetEnvironmentVariable Lib "kernel32" Alias "GetEnvironmentVariableA" (ByVal bsName As String, ByVal buff As String, ByVal ch As Long) As Long
  28. Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Any) As Long
  29. Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, ByVal lpBuffer As String, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, lpOverlapped As Any) As Long
  30.  
  31. 'Constants necessary for the Win32 API functions ReadFile and WriteFile
  32. Public Const STD_INPUT_HANDLE = -10&
  33. Public Const STD_OUTPUT_HANDLE = -11&
  34.  
  35. 'This list matches Netscape Enterprise Server.  Your Server's CGI
  36. 'environment variables may differ slightly.
  37. Global CGI_Server_Software As String
  38. Global CGI_Server_Name As String
  39. Global CGI_Server_URL As String
  40. Global CGI_Gateway_Interface As String
  41. Global CGI_Server_Protocol As String
  42. Global CGI_Server_Port As String
  43. Global CGI_Request_Method As String
  44. Global CGI_Path_Info As String
  45. Global CGI_Path_Translated As String
  46. Global CGI_Script_Name As String
  47. Global CGI_Query_String As String
  48. Global CGI_Remote_Host As String
  49. Global CGI_Remote_Addr As String
  50. Global CGI_Referer As String
  51. Global CGI_Auth_Type As String
  52. Global CGI_Remote_User As String
  53. Global CGI_Content_Type As String
  54. Global CGI_Content_Length As String
  55. Global CGI_HTTPS As String
  56. Global CGI_HTTPS_Key_Size As String
  57. Global CGI_HTTPS_Secret_Key_Size As String
  58. Global CGI_HTTP_Accept As String
  59. Global CGI_User_Agent As String
  60. Global CGI_If_Modified_Since As String
  61. Global CGI_HTTP_From As String
  62.  
  63. Global CGI_Version As String
  64. Global CGIname As String
  65.  
  66. Global glStdIn As Long
  67. Global gsBuff As String
  68. Global glBytesRead As Long
  69. Global glResult As Long
  70. Global gsStandardIn As String
  71.  
  72.  
  73.  
  74.  
  75. Sub DownloadFile()
  76. '
  77. 'Download the file to demonstrate that it was uploaded properly.
  78. '
  79. 'The CGI_Query_String will be in the following format:
  80. '    "download:filename"
  81. '
  82. 'This sub will open the file for output and send it to the browser
  83. 'as an octet stream.
  84. '
  85. Dim sFileName As String
  86.  
  87. sFileName = Right$(CGI_Query_String, Len(CGI_Query_String) - InStr(CGI_Query_String, ":"))
  88.  
  89. 'Check for the existence of the file to download.
  90. Dim lFileNumber, lBufSize As Long
  91. Dim sBuffer As String
  92.  
  93. sFileName = csUploadDir & "\" & sFileName
  94.  
  95. If Dir$(sFileName) = "" Then
  96.     SendHeader ("Error")
  97.     Send "Error: file " & sFileName & " was not found."
  98.     WriteLogFile "Error: <b>" & sFileName & "</b> was not found."
  99.     SendFooter
  100.     End
  101. End If
  102.  
  103. 'Get the file size in bytes
  104. lBufSize = FileLen(sFileName)
  105.  
  106. 'Open the file.
  107. lFileNumber = FreeFile   ' Get unused file number.
  108. Open sFileName For Binary Access Read As #lFileNumber
  109.  
  110. Send ("Content-type: application/octet-stream " & vbCrLf)
  111.  
  112. WriteLogFile "Began to download file " & sFileName
  113.  
  114. 'Do While Not EOF(lFileNumber) ' Loop until end of file.
  115.     sBuffer = Input(lBufSize, #lFileNumber)   'Get next 1024 characters.
  116.     Send sBuffer       'Send to the client browser.
  117. 'Loop
  118.  
  119. Close #lFileNumber
  120.  
  121. WriteLogFile "Finished download: " & sFileName
  122.  
  123. End
  124.  
  125. End Sub
  126.  
  127. Sub ErrorHandler()
  128.  
  129. SendHeader "<TITLE>Error in " & CGI_Script_Name & "</TITLE>"
  130. Send "<H1>Error in " & CGI_Script_Name & "</H1>"
  131. Send "An internal Visual Basic error <b>(" & Error & ")</b> has occurred in " & CGI_Script_Name & ".<br><br>"
  132. Send "Data posted to Standard in: <br><hr>" & gsStandardIn & "<br><hr>"
  133. Send "</BODY></HTML>"
  134.     
  135. WriteLogFile "***Error: " & Error
  136.         
  137. End  'Terminate the program
  138.  
  139. End Sub
  140.  
  141.  
  142.  
  143.  
  144. Function WriteLogFile(argString) As Boolean
  145. Dim sFileName As String
  146. Dim sFileNumber As Long
  147.  
  148. sFileName = "upload_cgi.log"
  149.  
  150. sFileNumber = FreeFile   ' Get unused file number.
  151. If Dir$(sFileName) = "" Then
  152.     Open sFileName For Output As #sFileNumber ' Create file.
  153. Else
  154.     Open sFileName For Append As #sFileNumber ' Append to file.
  155. End If
  156.     
  157. Print #sFileNumber, Format(Now, "YYYYMMDD hh:mm:ss AMPM") & _
  158.     ", CGI_Remote_Addr: " & CGI_Remote_Addr & _
  159.     ", " & argString
  160. Close #sFileNumber
  161.  
  162. End Function
  163.  
  164.  
  165. '=========================================
  166. ' Get CGI data for a Name used in the form
  167. '=========================================
  168. '
  169. ' Data is stored in the gsStandardIn as "name=value&name=value&..."
  170. ' The "name" = the value given to it in the form
  171. ' Ex: <INPUT NAME="uname" SIZE=30>
  172. ' "uname" is the NAME that would be used to obtain the value assigned
  173. ' to it when the form was submitted
  174. '
  175. Function GetCGIvalue(CGIname As String) As String
  176.  
  177. Dim CGIvalue As String 'Temporary place holder
  178. Dim valuepos, eqPos, amPos As Long
  179.  
  180. valuepos = InStr(1, gsStandardIn, CGIname + "=", 1) 'Use 1 for a case INSENSITIVE search
  181.     
  182. If valuepos = 0 Then 'What if the name is not found...
  183.     'This only happens for check boxes if they aren't filled in.
  184.     GetCGIvalue = "CGIName Not Found"
  185.  
  186. Else 'Get the data between the "=" and the next "&"
  187.     eqPos = InStr(valuepos, gsStandardIn, "=")
  188.     amPos = InStr(eqPos, gsStandardIn, "&")
  189.     
  190.     If amPos = 0 Then amPos = Len(gsStandardIn) + 1 'Must be the last value in the STDIN
  191.     If amPos - eqPos = 1 Then                   'Now what if they didn't enter any input ?
  192.         GetCGIvalue = ""
  193.     Else                                        'Now lets grab what's between the "=" and the "&"
  194.         CGIvalue = Mid$(gsStandardIn, eqPos + 1, amPos - eqPos - 1)
  195.     
  196.         'Lets decode the data (only if needed)
  197.         'URL encoded data contains "+" for spaces and replaces "?%+" characters that
  198.         'the user may have entered into "%<hex value>" Example: Line feed with return ="%0A%0D"
  199.         If InStr(CGIvalue, "+") Then CGIvalue = ReplaceTxt(CGIvalue, "+", " ")
  200.         If InStr(CGIvalue, "%") Then CGIvalue = ReplaceTxt(CGIvalue, "%", "HEX")
  201.         GetCGIvalue = CGIvalue
  202.     End If
  203. End If
  204. End Function
  205.  
  206. ' Get CGI Enviroment Variables
  207. '
  208. Function GetCGIenvVar(CGIvariable As String) As String
  209.  
  210. gsBuff = String(1024, 0)
  211.     glResult = GetEnvironmentVariable(CGIvariable, gsBuff, 1024) 'glResult returns the length of the value
  212.     If glResult Then
  213.         GetCGIenvVar = Left(gsBuff, glResult) 'trim string to the length of the actual data
  214.         Exit Function
  215.     End If
  216.         
  217. GetCGIenvVar = "Not available"
  218.  
  219. End Function
  220.  
  221.  
  222. Sub GetStandardInData()
  223.  
  224. 'Get the handle for Standard In
  225. glStdIn = GetStdHandle(STD_INPUT_HANDLE)
  226.  
  227. 'Get posted CGI data from STDIN
  228. Do
  229.     gsBuff = String(1024, 0)    ' Create a buffer big enough to hold the 1024 bytes
  230.     glBytesRead = 1024          ' Tell it we want at least 1024 bytes
  231.     If ReadFile(glStdIn, ByVal gsBuff, 1024, glBytesRead, ByVal 0&) Then 'Read the data
  232.         ' Add the data to our string
  233.         gsStandardIn = gsStandardIn & Left(gsBuff, glBytesRead)
  234.         If Len(gsStandardIn) = CGI_Content_Length Then
  235.             Exit Do 'All data has been received--Exit out of loop completely.
  236.         End If
  237.     End If
  238. Loop
  239.  
  240. End Sub
  241.  
  242.  
  243. '===========================================================
  244. ' Get the Enviroment variables we will use with this program
  245. '===========================================================
  246. ' Original Code by Paul Stohr (www.prplus.com)
  247. '
  248. ' Modified 4-11-96 by Kent Empie to match Netscape Commerce Server
  249. ' version 1.13 exactly.
  250. '
  251. ' When finished testing--comment out the ones that are not used to
  252. ' optimize for speed.
  253. '
  254. Sub InitCGIVariables()
  255.  
  256. CGI_Server_Software = GetCGIenvVar("SERVER_SOFTWARE")
  257. CGI_Server_Name = GetCGIenvVar("SERVER_NAME")
  258. CGI_Server_URL = GetCGIenvVar("SERVER_URL")
  259. CGI_Gateway_Interface = GetCGIenvVar("GATEWAY_INTERFACE")
  260. CGI_Server_Protocol = GetCGIenvVar("SERVER_PROTOCOL")
  261. CGI_Server_Port = GetCGIenvVar("SERVER_PORT")
  262. CGI_Request_Method = GetCGIenvVar("REQUEST_METHOD")
  263. CGI_Path_Info = GetCGIenvVar("PATH_INFO")
  264. CGI_Path_Translated = GetCGIenvVar("PATH_TRANSLATED")
  265. CGI_Script_Name = GetCGIenvVar("SCRIPT_NAME")
  266. CGI_Query_String = GetCGIenvVar("QUERY_STRING")
  267. CGI_Remote_Host = GetCGIenvVar("REMOTE_HOST")
  268. CGI_Remote_Addr = GetCGIenvVar("REMOTE_ADDR")
  269. CGI_Referer = GetCGIenvVar("HTTP_REFERER")
  270. CGI_Auth_Type = GetCGIenvVar("AUTH_TYPE")
  271. CGI_Remote_User = GetCGIenvVar("REMOTE_USER")
  272. CGI_HTTPS = GetCGIenvVar("HTTPS")
  273. CGI_HTTPS_Key_Size = GetCGIenvVar("HTTPS_KEYSIZE")
  274. CGI_HTTPS_Secret_Key_Size = GetCGIenvVar("HTTPS_SECRETKEYSIZE")
  275. CGI_HTTP_Accept = GetCGIenvVar("HTTP_ACCEPT")
  276. CGI_User_Agent = GetCGIenvVar("HTTP_USER_AGENT")
  277. CGI_If_Modified_Since = GetCGIenvVar("HTTP_IF_MODIFIED_SINCE")
  278. CGI_HTTP_From = GetCGIenvVar("HTTP_FROM")
  279. CGI_Content_Type = GetCGIenvVar("CONTENT_TYPE")
  280. CGI_Content_Length = GetCGIenvVar("CONTENT_LENGTH")
  281.  
  282. End Sub
  283.  
  284.  
  285. Sub SendSuccessMessage()
  286. 'This file upload confirmation can say just about anything.
  287. 'It is helpful to send some sort of a success message, as
  288. 'well as the file name and size in bytes.
  289. '
  290. 'In this case, we will also send back a directory list of all
  291. 'files that were uploaded to the "http_uploads" directory.
  292.  
  293. Dim sTempFileName As String
  294. Dim lTempCount As Long
  295.  
  296. Send "<h1>File Upload was Successful.</h1>"
  297.  
  298. Send "<blockquote>"
  299. Send "<br>"
  300. Send "<b>File Received: <i>" & gsOutputFileName & "</i>"
  301. Send "Size: <i>" & Format(glOutputFileLen, "###,###,###") & " bytes</i></b><br>"
  302. Send "<b>Submitted By: <i>" & CGI_Remote_User & "</i></b><br>"
  303. Send "<br>"
  304. Send "<br>"
  305. Send "</blockquote>"
  306. Send "The following is a list of files that has been uploaded to the Web server. "
  307. Send "You can click on the file names to download them.<br><br>"
  308.  
  309. 'Go through the uploads directory and echo each file back to the user.
  310. Send "<table>"
  311. Send "<tr><td></td><td>"
  312. Send "<b>File Name</b>"
  313. Send "</td><td>"
  314. Send "<b>File Size</b>"
  315. Send "</td><td>"
  316. Send "<b>File Date & Time</b>"
  317. Send "</td></tr>"
  318.     
  319. sTempFileName = Dir(csUploadDir & "\*.*")
  320. Do While sTempFileName <> ""
  321.     lTempCount = lTempCount + 1
  322.     
  323.     Send "<tr><td>" & lTempCount & ".</td><td>"
  324.     Send "<a href=" & CGI_Script_Name & "/" & sTempFileName & "?download:" & sTempFileName & ">"
  325.     Send sTempFileName
  326.     Send "</td><td>"
  327.     Send Format(FileLen(csUploadDir & "/" & sTempFileName), "###,###,###") & " bytes.</a>"
  328.     Send "</td><td>"
  329.     Send FileDateTime(csUploadDir & "/" & sTempFileName)
  330.     Send "</td></tr>"
  331.     
  332.     sTempFileName = Dir
  333. Loop
  334. Send "</table>"
  335.  
  336. End Sub
  337.  
  338.  
  339. Sub SendUploadForm()
  340. 'Send the Upload form to the user.  This is the form that includes the now
  341. 'official HTML 3.2 form field, "<input type=file>" and the multipart encoding.
  342.   
  343. SendHeader ("HTTP Upload Demo")
  344. Send ("<h2>Please Select a file to upload.</h1>")
  345.  
  346. Send "<FORM ENCTYPE=multipart/form-data ACTION=" & CGI_Script_Name & " METHOD=POST>"
  347. Send "<FONT SIZE = +1>Directions:</font>"
  348. Send "<ul>"
  349. Send "<li>Type in the full path name of the file to upload."
  350. Send "<li>-or- Hit the [Browse] button to find the file on your computer."
  351. Send "<li>Then hit the [Upload] button."
  352.  
  353. Send "</ul>"
  354.  
  355. Send "<blockquote>"
  356. Send "<table border=10 bgcolor=#CCCCCC><tr><td><br>"
  357. Send "<b>File Name...</b><br>"
  358. Send "<INPUT NAME=userfile SIZE=30 TYPE=file><br>"
  359. Send "<br>"
  360. Send "<center>"
  361. Send "<input type=""submit"" value=""Upload File"">"
  362. Send "</center><br>"
  363. Send "</td></tr></table>"
  364. Send "</blockquote>"
  365.  
  366. Send "<i><b>Note:</b> Please be patient with large files...You will "
  367. Send "not receive any notification until the file is completely transferred.<br>"
  368. Send "<br>"
  369. Send "</form>"
  370.  
  371. SendFooter
  372.  
  373. End Sub
  374. Sub Main()
  375. 'General VB4 CGI information:
  376. 'This Sub Main() is defined as the Startup Form (found in the menu under
  377. 'Tools, Options, Project)  All debugging can be done by writing to log files,
  378. 'or by using MsgBoxes if your console programs in NT have access to interact
  379. 'with the desktop.
  380.  
  381. 'About this Upload CGI program:
  382. 'This program implements an RFC 1867 HTTP file upload.
  383. '
  384. 'If called with a GET method, it sends a form to be filled out.
  385. 'This form includes the name of a file that is on the user's computer.
  386. 'The user can then select a local file from an open file dialogue box.
  387. 'When the use hits the submit button on the form, the file is sent
  388. 'to this program using the POST method.  This program then reads the
  389. 'posted data from standard in into the global variable 'gsStandardIn', parses
  390. 'out the file name and the body of the file by searching for MIME
  391. 'multipart boundaries.  Once the beginning and ending boundaries are
  392. 'located, the program writes the file as a binary file to a temporary
  393. 'directory.
  394. '
  395. 'Security Notice:
  396. 'The uploaded files should not be placed in a CGI directory, or in a
  397. 'Public HTTP directory without first doing a security assessment.
  398. '
  399. 'Obviously, some type of user authentication should be performed before
  400. 'allowing anyone to upload files to your server.
  401.  
  402. On Error GoTo CallErrorHandler
  403.  
  404. 'Intialize and get the enviroment variables first.
  405. InitCGIVariables
  406.  
  407. 'Assuming authentication is turned on, this is where you
  408. 'should add in some checking for user permissions.
  409.  
  410. 'If the program is called with the GET method and there is no query
  411. 'string, send back the upload form.  The upload form can be a plain HTML
  412. 'file--it does not have to be sent by this program.
  413. If CGI_Request_Method = "GET" Then
  414.     Select Case CGI_Query_String
  415.         Case "Not available"
  416.             SendUploadForm
  417.         Case Else
  418.             DownloadFile 'Download the file that is named in the CGI_Query_String.
  419.     End Select
  420.     End
  421. End If
  422.  
  423. SendHeader ("File Upload Example")
  424.  
  425. 'Get the posted data from standard in, and load it into the gsStandardIn string
  426. GetStandardInData
  427.  
  428. gsOutputFilePath = GetMultipartFormData("filename=")
  429. If Trim(gsOutputFilePath) = "" Then
  430.     Send ("<hr>")
  431.     Send ("<h2>Error -- No file name entered.</h2><br>")
  432.     Send ("Hit the BACK button and select a valid file name.<br>")
  433.     Send ("<hr>")
  434.     End
  435. End If
  436.     
  437. 'Strip off the path from the file.
  438. gsOutputFileName = StripOffPath(gsOutputFilePath)
  439.  
  440. ' Parse out the Uploaded file by its multipart MIME headers
  441. Dim sContentHeaderID, sEndContentHeaderID As String
  442. Dim lStartPos As Long
  443. Dim lStartFilePos, lEndFilePos As Long          'The determined positions of the
  444.                                                 'beginning and end of the file.
  445. If lStartPos = 0 Then
  446.     sContentHeaderID = Right$(CGI_Content_Type, Len(CGI_Content_Type) - (InStr(1, CGI_Content_Type, "boundary=") + 10))
  447.     sEndContentHeaderID = sContentHeaderID & "--"
  448.     
  449.     'Get the significant positions of the uploaded file.
  450.     lStartPos = InStr(1, gsStandardIn, "filename=")
  451.     
  452.     'The browser may or may not put a "Content-Type:" string after the file
  453.     'name but before the actual start of the file.  This depends on whether
  454.     'the file type is registered with the browser.  If it's there, find the
  455.     'first carriage return after it to locate the beginning of the file.
  456.     'Otherwise, the beginning of the file is after the filename="<file>".
  457.     If InStr(gsStandardIn, "Content-Type:") > 0 Then
  458.         lStartFilePos = InStr(InStr(lStartPos, gsStandardIn, "Content-Type:"), gsStandardIn, Chr$(13))
  459.         If lStartFilePos <= 0 Then
  460.             Error "Error locating starting file position."
  461.         End If
  462.     Else
  463.         lStartFilePos = InStr(InStr(lStartPos, gsStandardIn, "filename="), gsStandardIn, Chr$(13))
  464.         If lStartFilePos <= 0 Then
  465.             Error "Error locating starting file position."
  466.         End If
  467.     End If
  468.     lStartFilePos = lStartFilePos + 4  'Advance the start position four characters past the last chr$(13).
  469.     
  470.     'Uncomment the following for testing
  471.     'Send "lStartFilePos: " & lStartFilePos & "<br>"
  472.     'Dim x As Long
  473.     'For x = 1 To 170
  474.     '    Send x & ": <font color=#FF0000>" & Mid$(gsStandardIn, x, 1) & "</font> "
  475.     'Next x
  476.     'Send "<br>"
  477.     
  478.     lEndFilePos = InStr(lStartFilePos, gsStandardIn, sContentHeaderID)
  479.     If lEndFilePos = 0 Then 'No end in sight!
  480.         Send "<BR><BR><H2>No ending boundary found!</h2>"
  481.         Send "Last characters of gsStandardIn: " & Right$(gsStandardIn, 60) & "<br>"
  482.         Send "<br>Len(gsStandardIn): " & Len(gsStandardIn)
  483.         Send "<br>sContentHeaderID: " & sContentHeaderID
  484.         Send "<br>lStartPos: " & lStartPos
  485.         Send "<br>lStartFilePos: " & lStartFilePos
  486.  
  487.         Send ("<hr>")
  488.         SendTestCGIInfo
  489.         Send ("gsStandardIn: " & gsStandardIn)
  490.         SendFooter
  491.         End
  492.     Else
  493.         lEndFilePos = lEndFilePos - 6
  494.     End If
  495.         
  496.     glOutputFileLen = lEndFilePos - lStartFilePos
  497.    
  498. End If
  499.  
  500. 'Give error message if there was no file uploaded.
  501. If glOutputFileLen = 0 Then
  502.     Send ("<hr>")
  503.     Send ("<h2>Error -- File not uploaded.</h2><br>")
  504.     Send ("Hit the BACK button and select a valid file name.<br>")
  505.     Send ("<hr>")
  506.     End
  507. End If
  508.  
  509. Dim sOutput As String
  510.  
  511. sOutput = Mid$(gsStandardIn, lStartFilePos, glOutputFileLen)
  512.  
  513. 'Save the file to disk.
  514. Dim lBytesWritten, lFileHandle, lNumberOfBytesToWrite, glResult As Long
  515. Dim sBuffer As String
  516. Dim lFileNum As Long
  517.  
  518. lFileNum = FreeFile
  519.  
  520. 'Check to see that the http_uploads directory is there, and then save the file there.
  521. If Dir$(csUploadDir, vbDirectory) = "" Then 'Is the uploads directory there?
  522.     MkDir csUploadDir
  523. End If
  524.  
  525. gsOutputFileName = csUploadDir & "\" & LCase(gsOutputFileName)
  526.  
  527. WriteLogFile "User " & CGI_Remote_User & " uploaded " & gsOutputFileName & " " & glOutputFileLen & " bytes."
  528.  
  529. If Dir$(gsOutputFileName) <> "" Then
  530.     Kill gsOutputFileName  'Always overwrite the file for this demonstration.
  531. End If
  532.  
  533. Open gsOutputFileName For Binary As #lFileNum
  534. Put #lFileNum, 1, sOutput
  535. Close #lFileNum
  536.  
  537. SendSuccessMessage
  538. SendTestCGIInfo       ' echo back the environment variables for this demo
  539.  
  540. SendFooter
  541. End   'Terminate the CGI program.
  542.  
  543. CallErrorHandler:
  544.     Send "<br>lStartFilePos: " & lStartFilePos
  545.     Send "<br>lEndFilePos: " & lEndFilePos
  546.     Send "<br>gloutputFileLen: " & glOutputFileLen
  547.     Send "<br>sOutput: " & Left$(sOutput, 40) & "...<br>"
  548.     Send "<br>gsOutputFileName: " & gsOutputFileName & "<br>"
  549.     Send "<br>sContentHeaderID: " & sContentHeaderID & "<br>"
  550.  
  551.     Call ErrorHandler
  552.     
  553. End Sub
  554.  
  555.  
  556. Function GetMultipartFormData(argFieldName) As String
  557. ' Extract the uploaded file name from the MIME encoded string
  558. '
  559. Dim lStartFileNamePos, lFileNameLength As Long
  560.  
  561. On Error GoTo Error_Handler
  562.  
  563. lStartFileNamePos = InStr(gsStandardIn, argFieldName) + Len(argFieldName) + 1
  564. If lStartFileNamePos = 0 Then
  565.     GetMultipartFormData = ""
  566.     Exit Function
  567. End If
  568.  
  569. lFileNameLength = InStr(lStartFileNamePos + 1, gsStandardIn, """") - lStartFileNamePos
  570. If lFileNameLength = 0 Then
  571.     GetMultipartFormData = ""
  572.     Exit Function
  573. End If
  574.  
  575. GetMultipartFormData = Mid$(gsStandardIn, lStartFileNamePos, lFileNameLength)
  576.  
  577. Exit Function
  578.  
  579. Error_Handler:
  580.     WriteLogFile "Error in GetMultipartFormData: " & Error
  581.     GetMultipartFormData = ""
  582.  
  583. End Function
  584.  
  585. Function StripOffPath(argFileName) As String
  586. 'Locate the last "\" in the passed argument.
  587. 'when the last one is reached, strip off the full path,
  588. 'leaving the file name only.
  589.  
  590. Dim lPosFound, lLastPosFound As Long
  591.  
  592. lLastPosFound = 1
  593. lPosFound = 1
  594.  
  595. While lPosFound <> 0
  596.     lPosFound = InStr(lLastPosFound, argFileName, "\")
  597.     If lPosFound <> 0 Then lLastPosFound = lPosFound + 1
  598. Wend
  599.  
  600. StripOffPath = Right$(argFileName, Len(argFileName) - lLastPosFound + 1)
  601.  
  602. End Function
  603.  
  604.  
  605. Sub SendTestCGIInfo()
  606. 'Dump the environment variables back to the user for testing purposes.
  607.  
  608. Send "<H1>CGI & Enviroment Output</H1>"
  609. Send "<hr size=3>"
  610. Send "CGI_Server_Software = " & CGI_Server_Software & "<br>"
  611. Send "CGI_Server_Name = " & CGI_Server_Name & "<br>"
  612. Send "CGI_Server_URL = " & CGI_Server_URL & "<br>"
  613. Send "CGI_Gateway_Interface = " & CGI_Gateway_Interface & "<br>"
  614. Send "CGI_Server_Protocol = " & CGI_Server_Protocol & "<br>"
  615. Send "CGI_Server_Port = " & CGI_Server_Port & "<br>"
  616. Send "CGI_Request_Method = " & CGI_Request_Method & "<br>"
  617. Send "CGI_Path_Info = " & CGI_Path_Info & "<br>"
  618. Send "CGI_Path_Translated = " & CGI_Path_Translated & "<br>"
  619. Send "CGI_Script_Name = " & CGI_Script_Name & "<br>"
  620. Send "CGI_Query_String = " & CGI_Query_String & "<br>"
  621. Send "CGI_Remote_Host = " & CGI_Remote_Host & "<br>"
  622. Send "CGI_Remote_Addr = " & CGI_Remote_Addr & "<br>"
  623. Send "CGI_Referer = " & CGI_Referer & "<br>"
  624. Send "CGI_Auth_Type = " & CGI_Auth_Type & "<br>"
  625. Send "CGI_Remote_User = " & CGI_Remote_User & "<br>"
  626. Send "<b>CGI_Content_Type = " & CGI_Content_Type & "<br></b>"
  627. Send "<b>CGI_Content_Length = " & CGI_Content_Length & "<br></b>"
  628. Send "CGI_HTTPS = " & CGI_HTTPS & "<br>"
  629. Send "CGI_HTTPS_Key_Size = " & CGI_HTTPS_Key_Size & "<br>"
  630. Send "CGI_HTTPS_Secret_Key_Size = " & CGI_HTTPS_Secret_Key_Size & "<br>"
  631. Send "CGI_HTTP_Accept = " & CGI_HTTP_Accept & "<br>"
  632. Send "CGI_User_Agent = " & CGI_User_Agent & "<br>"
  633. Send "CGI_If_Modified_Since = " & CGI_If_Modified_Since & "<br>"
  634. Send "CGI_HTTP_From = " & CGI_HTTP_From & "<br>"
  635.  
  636. End Sub
  637.  
  638.  
  639.  
  640.  
  641.  
  642. Sub SendHeader(argTitle As String)
  643. 'Notice:  When CGI's are sending HTML to a Web server, they must always
  644. 'follow the 'Content-type: text/html' with two carriage returns/line feeds
  645. '
  646. 'Visual Basic recognized 'vbCrLf' as being a carriage return and a line feed.
  647.  
  648. Send ("Content-type: text/html" & vbCrLf & vbCrLf)
  649. Send ("")
  650. Send ("<HTML><HEAD><TITLE>" & argTitle & "</TITLE></HEAD>")
  651. Send ("<BODY>")
  652.  
  653. End Sub
  654.  
  655.  
  656. Sub SendFooter()
  657. 'Send a standard HTML footer.
  658.  
  659. Send "<br>"
  660. Send "<hr>"
  661. Send "<FONT SIZE=-1>Do you have any feedback concerning this code?  Please send it to "
  662. Send "<a href=""mailto:kempie@chesco.com"">Kent Empie</a>.  Thanks.</FONT>"
  663. Send ("</BODY></HTML>")
  664.  
  665. End Sub
  666.  
  667.  
  668.  
  669. ' Send HTML output to standard out using the Win32API call "WriteFile"
  670. '
  671. Sub Send(argString As String)
  672.  
  673. Dim glResult As Long
  674.     WriteFile GetStdHandle(STD_OUTPUT_HANDLE), argString & vbCrLf, Len(argString) + 2, glResult, ByVal 0&
  675. End Sub
  676.  
  677. '=============================================
  678. 'Decode and replace the URL encoded data
  679. '=============================================
  680. ' Original Code by Paul Stohr (www.prplus.com)
  681. '
  682. ' Data that we get back from STDIN will be URL encoded meaning that any spaces
  683. ' will be replaced with "+" and special characters will be replaced with
  684. ' "%<Hex value>" Example: Line feed and carriage return = "%0A%0D"
  685. '
  686. ' NOTE: You should replace the "+" with spaces first since a "+" that a user
  687. '       may have entered will be URL encoded. By decoding "+" first to spaces
  688. '       will reduce the risk of replaceing a "+" that a user might have entered
  689. '       in the form.
  690. '
  691. '   rpText  = the text string to be decoded
  692. '   srchStr = the character to search for
  693. '           Note: Use "+" for spaces and "%" for "%<HEX value>"
  694. '
  695. '   rpCmd   = the character to replace the srchStr with
  696. '           Note: Use " " for spaces (obviously) and "HEX" for "%<HEX value>"
  697. '
  698. Public Function ReplaceTxt(ByVal rpText As String, ByVal srchStr As String, ByVal rpCmd As String) As String
  699. Dim xString, perCnt As Long
  700.  
  701. xString = 1                                  'We want to start at position 1
  702. Do
  703.     perCnt = InStr(xString, rpText, srchStr) 'Find the pos. of the next character
  704.     If perCnt = 0 Then Exit Do               'No more found, Stop decoding
  705.     If UCase(rpCmd) = "HEX" Then             'Lets replace the "%<HEX value>"
  706.         rpText = Left$(rpText, perCnt - 1) & Chr(Val("&H" & (Mid$(rpText, perCnt + 1, 2)))) & Right$(rpText, Len(rpText) - perCnt - 2)
  707.         xString = perCnt + 1
  708.     Else                                     'Lets replace the srchStr with rpCMD
  709.         rpText = Left$(rpText, perCnt - 1) & rpCmd & Right$(rpText, Len(rpText) - perCnt - Len(srchStr) + 1)
  710.         xString = perCnt + Len(rpCmd)
  711.     End If
  712. Loop
  713. ReplaceTxt = rpText
  714. End Function
  715.  
  716.  
  717.  
  718.  
  719.