ActiveVFP
ActiveVFP (also known as AVFP) is a server-side scripting framework designed for Web development to produce dynamic Web pages. Similar to PHP, but using the native Visual Foxpro (VFP) language and database (or other databases like Microsoft SQL and MySQL), ActiveVFP can also be used in Model-View-Controller (MVC) web applications as well as RESTful API.  ActiveVFP is completely free and open source and does not require the purchase of Microsoft Visual FoxPro or any additional software.

ActiveVFP was originally created in 2001. The main implementation of ActiveVFP is now produced by the Foxpro Community at  and serves as the formal reference to ActiveVFP. ActiveVFP is free software released under the MIT License.

ActiveVFP is unique among server-side web languages and frameworks because it has a database and database functionality built into the language.

Syntax

ActiveVFP uses the native Visual Foxpro language as it exists in the latest version produced by Microsoft, Visual FoxPro 9 SP2.  The multi-threaded VFP runtime, vfp9t.dll,  is used instead of the regular desktop version of the VFP runtime.

Using ActiveVFP, the VFP compiler only executes VFP code within its delimiters. Anything outside its delimiters is not processed by VFP. The most common delimiters are ASP-style short forms <% or <%= and %>. <% %> executes a FoxPro code block and <%=  %> prints the variable out immediately.   The purpose of all these delimiters is to separate VFP code from non-VFP code, including HTML.

The main objects available to ActiveVFP for web programming are: oRequest, oResponse, and oSession (and all of the objects that have been available in Classic Active Server Pages (ASP)).  These objects are used entirely within Visual FoxPro to accomplish web programming with FoxPro.

The FoxPro language contains commands quite similar to other programming languages such as Basic. Loops include do, if, while, for, else commands in a usage easily understood by anyone familiar with other programming languages. Commands take the form of "command" and "endcommand".  The language also has extensive database manipulation and indexing commands.

Like PHP, ActiveVFP takes advantage of automatic memory Garbage Collection (GC) and Dynamic/Weak Typing, boosting programmer productivity.

In addition to “scripting” mode, ActiveVFP offers Model-View-Controller(MVC) design as well.  The Controller consists of FoxPro class code located in a Foxpro .prg file.  Output can consist of .avfp views, JSON, and others, similar to other modern MVC implementations.  The Model can be DBF files or other back end databases.

Examples 
 VFP code embedded in HTML code to open table and list records
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>VFP code in HTML</title>
...
<% 
*Settings
 lnTotPerPage  =10       
 lnpagenumbers =5         
 lnStart=VAL(oRequest.querystring("page"))  
 lcButton=oRequest.querystring("nav")       
*sql
 SELE * FROM Customer INTO CURSOR tCursor 
*create page numbers
 START=0
 lnPageMax = 0
 lnPageBegin = 0
 lnRowCount = RECCOUNT()
 SET PROC to oProp.AppStartPath+'prg\pages' ADDITIVE   
 lcPages= pages(lnTotPerPage,lnpagenumbers,lnStart,lcButton,lnRowCount)
%>
...
 <% FOR lnX = lnPageBegin TO lnPageMax 
     IF lnX <= lnRowCount
      GOTO lnX %>
      <tr>
        <td width="40%"><font face="helvetica, arial" size="2">
	<a hhref="<%=JustPath(oProp.ScriptPath)+[/detail.avfp?cust_id=]+;
         ALLTRIM(cust_id)%>"><%=tCursor.company%></a></font></td>
        <td width="36%"><font face="helvetica, arial" size="2">
	<%=tCursor.Contact%></font></td>
        <td width="24%"><font face="helvetica, arial" size="2" color="#000000">
	<%=tCursor.Title %></font></td>
      </tr>
<%   ENDIF
   ENDFOR %>                               
...
<%= lcPages %>

 VFP Controller code for an MVC web application
* customers.prg -Customers Controller
* * bypasses Main.prg and .AVFP script code
* 
DEFINE CLASS customersController AS restController
 *
 PROCEDURE openData
  SELECT 0
  USE (THIS.homeFolder + "customers.dbf") ALIAS customers
 ENDPROC
 
 PROCEDURE infoAction && GET www.hostname.com/app/customers/info
  RETURN "homeFolder: <b>" + THIS.homeFolder + "</b>"
 ENDPROC
 
 PROCEDURE getAction && GET www.hostname.com/app/customers/<id>
  LOCAL cCustId
  cCustId = THIS.Params[1]
  THIS.openData()
  SELECT CUSTOMERS
  LOCATE FOR custId = cCustId
  IF FOUND()
   LOCAL cJSON
   **USE mydbf  &&test error
   *quick and dirty JSON
   cJSON = [{"custId":"] + RTRIM(custId) + [","custName":"] + RTRIM(custName) + [",] + ;
           ["custStat":"] + RTRIM(custStat) + ["}]
   RETURN cJSON 
  ENDIF
 ENDPROC
 
 PROCEDURE listAction  && GET www.hostname.com/app/customers/
  LOCAL cHTML
  cHTML = ""
  *oEmp=newOBJECT('schedbizobj','c:\avfp5.61Demo\prg\utiltest2.prg')
  SET PROC to substr(oProp.AppStartPath,1,AT([\],oProp.AppStartPath,2))+'prg\AVFPutilities' ADDITIVE   && Make sure you use ADDITIVE or bad things happen!
  THIS.openData()
  SELECT CUSTOMERS
  cHTML= oHTML.mergescript(FILETOSTR(substr(oProp.AppStartPath,1,AT([\],oProp.AppStartPath,2))+'viewtest.avfp'))
  RETURN cHTML 
 ENDPROC
 
 PROCEDURE helloworld      && custom method (&& GET www.hostname.com/app/customers/helloworld/)
  LOCAL cHTML
  cHTML = ""
  *USE mydbf
  *SET PROC to substr(oProp.AppStartPath,1,AT([\],oProp.AppStartPath,2))+'prg\AVFPutilities' ADDITIVE   && Make sure you use ADDITIVE or bad things happen!
  cHTML= oHTML.mergescript(FILETOSTR(substr(oProp.AppStartPath,1,AT([\],oProp.AppStartPath,2))+'hello.avfp'))
  RETURN cHTML 
 ENDPROC
 
 PROCEDURE getemployees      && custom method   (&& GET www.hostname.com/app/customers/getemployee/<id>
  
	oJSON=NEWOBJECT('json','json.prg')
    
    SET PATH TO oProp.AppStartPath+'data\AVFPdemo41\'
	
	select e.emp_id as id, e.first_Name as firstName, e.last_Name as lastName, e.title as title, [images/Emps/]+e.picture as picture,count(r.emp_id) as reportCount ;
	from employee e left join employee r on VAL(r.reports_to) = VAL(e.emp_id) ;
	INTO Cursor SearchResults;
	group by e.last_Name,e.emp_id, e.first_Name,e.title, e.picture ;
	order by e.last_Name,e.first_Name

	oJSON.keyforcursors="items"

	* send JSON data and properties back
	oResponse.ContentType = "application/json;charset=utf-8"  
	oResponse.Write(oJSON.stringify('SearchResults'))
	oResponse.Flush
	lcHTMLout=[]
 ENDPROC

************************************************************************

ENDDEFINE