.. index:: single: Web Development (CGI Library); Introduction ============================= Web Development (CGI Library) ============================= In this chapter we will learn about developing Web applications using a CGI Library written in the Ring language. .. index:: pair: Web Development (CGI Library); Configure the Apache web server Configure the Apache web server =============================== We can use Ring with any web server that support CGI. In this section we will learn about using Ring with the Apache HTTP Server. You can download Apache from : http://httpd.apache.org/ Or you can get it included with other projects like XAMPP : https://www.apachefriends.org/download.html Install then open the file: .. code-block:: none xampp\apache\conf\httpd.conf search for .. code-block:: none Then after it add .. code-block:: none Options FollowSymLinks +ExecCGI So we have .. code-block:: none Options FollowSymLinks +ExecCGI Search for the next line and be sure that it's not commented .. code-block:: none LoadModule cgi_module modules/mod_cgi.so Search for : AddHandler cgi-script Then add ".ring" to the supported cgi extensions Example .. code-block:: none AddHandler cgi-script .cgi .ring Example .. code-block:: none AddHandler cgi-script .cgi .pl .asp .ring Run/Start the server Create your web applications in a directory supported by the web server. Example: .. code-block:: none Apache2.2\htdocs\mywebapplicationfolder Example: .. code-block:: none xampp\htdocs\mywebapplicationfolder Inside the source code file (*.ring), Add this line .. code-block:: ring #!ring -cgi .. note:: Change the previous line based on the path to ring.exe in your machine .. index:: pair: Web Development (CGI Library); Ring CGI Hello World Program Ring CGI Hello World Program ============================ The next program is the Hello World program .. code-block:: ring #!ring -cgi See "content-type : text/html" +nl+nl+ "Hello World!" + nl .. index:: pair: Web Development (CGI Library); Hello World Program using the Web Library Hello World Program using the Web Library ========================================= We can use the web library to write CGI Web applications quickly Example (1) : .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web New Page { Text("Hello World!") } Example (2) : .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web WebPage() { Text("Hello World!") } .. tip:: the difference between ex. 1 and ex. 2 is using WebPage() function to return the page object instead of creating the object using new statement. .. index:: pair: Web Development (CGI Library); Web Library Features Web Library Features ==================== The next features are provided by the Web library to quickly create web applications. * Generate HTML pages using functions * Generate HTML pages using objects * HTTP Get * HTTP Post * Files Upload * URL Encode * Templates * CRUD MVC Sample * Users Logic & Registration Sample .. index:: pair: Web Development (CGI Library); HTTP Get Example HTTP Get Example ================ The Page User Interface .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web New Page { Title = "Test HTTP Get" divstart([ :style = StyleSizeFull() ] ) boxstart() text( "Test HTTP GET" ) newline() boxend() divstart([ :style = Styledivcenter("600px","550px") + StyleGradient(21) ]) divstart([:style = stylefloatleft() + stylesize("100px","100%") + stylecolor("black") + stylegradient(58)]) formstart("ex5.ring") tablestart([ :style = stylesize("65%","90%") + stylemarginleft("35%") + stylemargintop("30%") ]) rowstart([]) cellstart([]) text ( "Name : " ) cellend() cellstart([]) cTextboxStyle = StyleMarginLeft("5%") + StyleWidth("250px") + StyleColor("black") + StyleBackColor("white") textbox([ :name = "Name", :style = cTextboxStyle ] ) cellend() rowend() rowstart([]) cellstart([]) text ( "Address : " ) cellend() cellstart([]) textbox([ :name = "Address", :style = cTextboxStyle] ) cellend() rowend() rowstart([]) cellstart([]) text ( "Phone : " ) cellend() cellstart([]) textbox([ :name = "Phone", :style = cTextboxStyle ]) cellend() rowend() rowstart([]) cellstart([]) text ( "Age : " ) cellend() cellstart([]) textbox([ :name = "Age", :style = cTextboxStyle ]) cellend() rowend() rowstart([]) cellstart([]) text ( "City: " ) cellend() cellstart([]) listbox([ :name = "City", :items = ["Cairo","Riyadh","Jeddah"], :style = stylemarginleft("5%") + stylewidth("400px") ] ) cellend() rowend() rowstart([]) cellstart([]) text ( "Country : " ) cellend() cellstart([]) combobox([ :name = "Country", :items = ["Egypt","Saudi Arabia","USA"], :style = stylemarginleft("5%") + stylewidth("400px")+ stylecolor("black")+ stylebackcolor("white")+ stylefontsize("14px") ]) cellend() rowend() rowstart([]) cellstart([]) text ( "Note : " ) cellend() cellstart([]) editbox([ :name = "Notes", :style = stylemarginleft("5%") + stylesize("400px","100px")+ stylecolor("black")+ stylebackcolor("white") , :value = "write comments here..." ] ) cellend() rowend() rowstart([]) cellstart([]) cellend() cellstart([]) submit([ :value = "Send" , :Style = stylemarginleft("5%") ]) cellend() rowend() tableend() formend() divend() divend() divend() } Screen Shot: .. image:: ex4.jpg :alt: HTTP Get The Response .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web New Page { divstart([ :style = styledivcenter("800px","500px") ]) boxstart() text ( "HTTP GET Response" ) newline() boxend() divstart([ :style = stylefloatleft()+stylewidth("10%")+ stylecolor("black")+stylegradient(58) ]) newline() text ( "Name : " ) newline() newline() text ( "Address : " ) newline() newline() text ( "Phone : " ) newline() newline() text ( "Age : " ) newline() newline() text ( "City : " ) newline() newline() text ( "Country : " ) newline() newline() text ( "Note : " ) newline() newline() divend() divstart([ :style = stylefloatleft()+stylewidth("90%")+ stylecolor("black")+stylegradient(47) ]) divstart([ :style = stylefloatleft() + stylewidth("1%") ]) newline() divend() divstart([ :style = stylefloatleft() + stylewidth("95%") ]) newline() text ( aPageVars["Name"] ) newline() newline() text ( aPageVars["Address"] ) newline() newline() text ( aPageVars["Phone"] ) newline() newline() text ( aPageVars["Age"] ) newline() newline() text ( aPageVars["City"] ) newline() newline() text (aPageVars["Country"] ) newline() newline() text ( aPageVars["Notes"] ) newline() newline() divend() divend() divend() } Screen Shot: .. image:: ex5.jpg :alt: HTTP Get .. index:: pair: Web Development (CGI Library); HTTP POST Example HTTP POST Example ================= The Page User Interface .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web New Page { boxstart() text( "Post Test") newline() boxend() divstart([ :style=StyleFloatLeft()+StyleWidth("100px") ]) newline() text( "Number1 : " ) newline() newline() text( "Number2 : " ) newline() newline() divend() formpost("ex7.ring") divstart([ :style = styleFloatLeft()+StyleWidth("200px") ]) newline() textbox([ :name = "Number1" ]) newline() newline() textbox([ :name = "Number2" ]) newline() newline() submit([ :value = "Send" ] ) divend() formend() } Screen Shot: .. image:: ex6.jpg :alt: HTTP Post The Response .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web New Page { boxstart() text( "Post Result" ) newline() boxend() divstart([ :style = styleFloatLeft()+styleWidth("200px") ]) newline() text( "Number1 : " + aPageVars["Number1"] ) newline() newline() text( "Number2 : " + aPageVars["Number2"] ) newline() newline() text( "Sum : " + (0 + aPageVars["Number1"] + aPageVars["Number2"] ) ) newline() divend() } Screen Shot: .. image:: ex7.jpg :alt: HTTP Post .. index:: pair: Web Development (CGI Library); Upload Files Upload Files ============ The Page User Interface .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web New page { boxstart() text( "Upload File" ) newline() boxend() for x = 1 to 3 newline() next formupload("ex9.ring") text( "Customer Name : " ) textbox([ :name = "custname" ]) newline() newline() divstart([ :style = styleFloatLeft() + styleWidth("90px") ]) uploadfile("file") newline() newline() uploadfile("file2") newline() newline() submit([ :value = "Send" ]) divend() formend() } Screen Shot: .. image:: ex8.jpg :alt: Upload File The Response .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web cUploadPath = "C:/Apache2.2/htdocs/ringapp/upload/" cUploadFolder = "/ringapp/upload/" New page { boxstart() text( "Upload Result" ) newline() boxend() newline() divstart([ :style= styleFloatLeft() + styleWidth("100px") ]) text( "Name : " + aPageVars["custname"] ) newline() divend() if aPageVars["file"] != char(13) getuploadedfile(self,"file") ok if aPageVars["file2"] != char(13) getuploadedfile(self,"file2") ok } Func getuploadedfile oObj,cFile # here we use object.property # instead of object { } to avoid executing braceend method cFileName = cUploadPath + oObj.getfilename(aPageVars,cFile) write(cFileName,aPageVars[cFile]) system("chmod a+x "+cFileName) oObj.newline() oObj.text( "File "+cFileName+ " Uploaded ..." ) oObj.newline() imageURL = cUploadFolder + oObj.getfilename(aPageVars,cFile) oObj.link([ :url = imageURL, :title = "Download" ]) oObj.newline() oObj.image( [ :url = imageURL , :alt = :image ] ) oObj.newline() Screen Shot: .. image:: ex9.jpg :alt: Upload File .. index:: pair: Web Development (CGI Library); Cookies Cookies ======= The Page User Interface .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web New page { boxstart() text( "Cookie Test" ) newline() boxend() newline() link([ :url = "ex11.ring", :title = "Use Cookies" ]) cookie("custname","Mahmoud Fayed") cookie("custage",28) } Screen Shot: .. image:: ex10.jpg :alt: Cookies The Response .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web New Page { boxstart() text( "Cookies Values" ) newline() boxend() link([ :url = "ex10.ring", :title = "back" ]) newline() divstart([:style="float:left;width:200px"]) text( "Name : " + aPageVars["custname"] ) newline() text( "Age : " + aPageVars["custage"] ) newline() divend() } Screen Shot: .. image:: ex11.jpg :alt: Cookies .. index:: pair: Web Development (CGI Library); URL Encode URL Encode ========== The Page User Interface .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web New Page { boxstart() text( "URLEncode" ) newline() boxend() link([ :url = "ex5.ring?Name="+URLEncode("-*{Mahmoud}*-")+ "&Address=Egypt&Phone=123456&Age=28&Notes=Programmer", :title = "Test URL Encode" ]) } Screen Shot: .. image:: ex12.jpg :alt: URL Encode Screen Shot: .. image:: ex12r.jpg :alt: URL Encode .. index:: pair: Web Development (CGI Library); Templates Templates ========= Using Templates we can write Ring code inside HTML files Syntax: .. code-block:: html <%= Ring Expression %> <% Ring Statements %> The HTML Code .. code-block:: html

Listing Numbers

<% for x in aNumbers %> <% next %>
<%= myheader.cColumn1 %> <%= myheader.cColumn2 %>
<%= x.nValue %> <%= x.nSquare %>
The Ring Code .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web New NumbersController { start() } Class NumbersController MyHeader aNumbers Func Start MyHeader = New Header { cColumn1 = "Number" cColumn2 = "Square" } aNumbers = list(20) for x = 1 to len(aNumbers) aNumbers[x] = new number { nValue = x nSquare = x*x } next cTemp = Template("mynumbers.html",self) New Page { boxstart() text( "Test Templates" ) newline() boxend() html(cTemp) } Class Header cColumn1 cColumn2 Class Number nValue nSquare Screen Shot: .. image:: ex13.jpg :alt: Templates .. index:: pair: Web Development (CGI Library); HTML Special Characters HTML Special Characters ======================= The text() function display HTML special characters. If you want to write html code, use the html() function. .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web New Page { boxstart() text("HTML Special Characters") newline() boxend() text('

"hello world"

') } Screen Shot: .. image:: ex14.jpg :alt: HTML Special Characters .. index:: pair: Web Development (CGI Library); Hash Functions Hash Functions ============== The Page User Interface .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web New Page { boxstart() text( "Hash Test") newline() boxend() divstart([ :style = StyleFloatLeft() + StyleWidth("100px") ]) newline() text( "Value : " ) newline() newline() divend() formpost("ex16.ring") divstart([ :style = StyleFloatLeft() + StyleWidth("300px") ]) newline() textbox([ :name = "Value" ]) newline() newline() submit([ :value = "Send" ]) divend() formend() } Screen Shot: .. image:: ex15.jpg :alt: Hash Functions The Response .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web New Page { boxstart() text( "Hash Result" ) newline() boxend() divstart([ :style = styleFloatLeft() + styleWidth("100%") ]) newline() text( "Value : " + aPageVars["Value"] ) newline() text( "MD5 : " + MD5(aPageVars["Value"]) ) newline() text( "SHA1 : " + SHA1(aPageVars["Value"]) ) newline() text( "SHA256 : " + SHA256(aPageVars["Value"]) ) newline() text( "SHA224 : " + SHA224(aPageVars["Value"]) ) newline() text( "SHA384 : " + SHA384(aPageVars["Value"]) ) newline() text( "SHA512 : " + SHA512(aPageVars["Value"]) ) newline() divend() } Screen Shot: .. image:: ex16.jpg :alt: Hash Functions .. index:: pair: Web Development (CGI Library); Random Image Random Image ============ .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web cUploadPath = "C:/Apache2.2/htdocs/ringapp/upload/" New Page { boxstart() text( "Random Test") newline() boxend() divstart([ :style = styleFloatLeft() + styleWidth("400px") ]) newline() aList = dir(cUploadPath) if len(aList) > 0 nIndex = random(len(aList)) if nindex = 0 nIndex = 1 ok cItem = "upload/" + aList[nIndex][1] newline() image( [ :url = cItem , :alt = :image ] ) else text("No images!") newline() ok divend() } Screen Shot: .. image:: ex17.jpg :alt: Random Image .. index:: pair: Web Development (CGI Library); HTML Lists HTML Lists ========== The next example print a list contains numbers from 1 to 10 Then print a list from Ring List. Finally we have a list of buttons and when we press on a button we get a message contains the clicked button number. To start the list we uses the ulstart() function. To end the list we uses the ulend() function. We uses listart() and liend() to determine the list item. .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web Func Main New Page { ulstart([]) for x = 1 to 10 listart([]) text(x) liend() next ulend() list2ul(["one","two","three","four","five"]) ulstart([]) for x = 1 to 10 listart([]) cFuncName = "btn"+x+"()" button([ :onclick = cFuncName , :value = x]) script(scriptfuncalert(cFuncName,string(x))) liend() next ulend() } Screen Shot: .. image:: ex18.jpg :alt: HTML Lists .. index:: pair: Web Development (CGI Library); HTML Tables HTML Tables =========== In this example we will learn how to generate HTML tables using the tablestart(), tableend(), rowstart(), rowend() ,headerstart(), headerend(), cellstart() and cellend() functions. .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web Func Main New Page { divstart([ :style = styledivcenter("400px","500px") ] ) style(styletable() + styletablerows("t01")) tablestart([ :id = :t01 , :style = stylewidth("100%") ]) rowstart([]) headerstart([]) text("Number") headerend() headerstart([]) text("square") headerend() rowend() for x = 1 to 10 rowstart([]) cellstart([]) text(x) cellend() cellstart([]) text(x*x) cellend() rowend() next tableend() divend() } Screen Shot: .. image:: ex19.jpg :alt: HTML Tables .. index:: pair: Web Development (CGI Library); Gradient Gradient ======== In this example we will learn how to use the StyleGradient() function. The function takes the style number as input (range from 1 to 60). .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web Func Main New Page { boxstart() text("StyleGradient() Function") boxend() for x = 1 to 60 divstart([ :id = x , :align = "center" , :style = stylefloatleft() + stylesize(string(100/60*6)+"%","50px") + stylegradient(x) ]) h3(x) divend() next } Screen Shot: .. image:: ex20.jpg :alt: Gradient .. index:: pair: Web Development (CGI Library); Generating Pages using Objects Generating Pages using Objects ============================== Instead of using functions/methods to generate HTML pages, we can use an object for each element in the page. This choice means more beautiful code but slower. The fastest method is to print HTML code directly, then using functions then using templates then using objects (slower). .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web Func Main WebPage() { Title = "Using objects to create the Web Page content" h1 { text("welcome") } link { Title = "Google" Link = "http://www.google.com" } div { id = "div1" style = stylegradient(30) + stylesize("50%","50%") text("Outer Div") div { id = "div2" color = "white" backgroundcolor = "green" width = "50%" height = "50%" marginleft = "5%" margintop = "5%" text("Inner Div") } } div { id = "div3" color = "black" backgroundcolor = "silver" width = "100%" height = "100%" text("Form") form { method = "POST" Action = "helloworld.ring" Table { style = stylewidth("100%") + stylegradient(24) TR { TD { WIDTH="10%" text("Name : " ) } TD { Input { type = "text" } } } TR { TD { WIDTH="10%" text("Email : " ) } TD { Input { type = "text" } } } TR { TD { WIDTH="10%" text("Password : " ) } TD { Input { type = "password" } } } TR { TD { WIDTH="10%" text("Notes") } TD { TextArea { width="100%" rows = 10 cols = 10 text("type text here...") } } } TR { TD { WIDTH="10%" text("Gender") } TD { select { width = "100%" option { text("Male") } option { text("Female") } } } } TR { TD { WIDTH="10%" text("Role") } TD { select { multiple = "multiple" width = "100%" option { text("student") } option { text("admin") } } } } } Input { type = "submit" value = "send" } Image { src="upload/profile1.jpg" alt="profile"} Input { type = "checkbox" value = "Old Member"} text("old member") Input { type = "range" min=1 max=100} Input { type = "number" min=1 max=100} Input { type = "radio" color="black" name="one" value = "one"} text("one") } } div { color = "white" backgroundcolor = "blue" width = "100%" UL { LI { TEXT("ONE") } LI { TEXT("TWO") } LI { TEXT("THREE") } } } div { audio { src = "horse.ogg" type = "audio/ogg" } video { width = 320 height = 240 src = "movie.mp4" type = "video/mp4" } Input { type = "color" value = "#ff0000" onchange = "clickColor(0, -1, -1, 5)" } } } Screen Shot: .. image:: ex21.jpg :alt: Using Objects .. image:: ex21_2.jpg :alt: Using Objects - part 2 .. index:: pair: Web Development (CGI Library); HtmlPage Class HtmlPage Class ============== Using this class we can create HTML documents without printing the output to the standard output So instead of using the WebLib in Web Applications only We can use it in Console/GUI/Mobile Applications too Example: .. code-block:: ring load "stdlib.ring" load "weblib.ring" import System.Web func main mypage = new HtmlPage { h1 { text("Customers Report") } Table { style = stylewidth("100%") + stylegradient(4) TR { TD { WIDTH="10%" text("Customers Count : " ) } TD { text (100) } } } Table { style = stylewidth("100%") + stylegradient(26) TR { style = stylewidth("100%") + stylegradient(24) TD { text("Name " ) } TD { text("Age" ) } TD { text("Country" ) } TD { text("Job" ) } TD { text("Company" ) } } for x = 1 to 100 TR { TD { text("Test" ) } TD { text("30" ) } TD { text("Egypt" ) } TD { text("Sales" ) } TD { text("Future" ) } } next } } write("report.html",mypage.output()) .. index:: pair: Web Development (CGI Library); Using Bootstrap Library using Functions Using Bootstrap Library using Functions ======================================= The next example uses the Bootstrap JavaScript Library when generating the HTML page. .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web Func Main new BootstrapPage { divstart([ :class = "container" ]) divstart([ :class = "jumbotron" ]) h1("Bootstrap Page") divend() divstart([ :class = :row ]) divstart([ :class = "col-sm-4" ]) h3("Welcome to the Ring programming language") p([ :text = "Using a scripting language is very fun!" ]) divend() divstart([ :class = "col-sm-4" ]) h3("Welcome to the Ring programming language") p([ :text = "using a scripting language is very fun!" ]) divend() divstart([ :class = "col-sm-4" ]) h3("Welcome to the Ring programming language") p([ :text = "using a scripting language is very fun!" ]) divend() divend() divend() } Screen Shot: .. image:: ex22.jpg :alt: Bootstrap .. index:: pair: Web Development (CGI Library); Using Bootstrap Library using Objects Using Bootstrap Library using Objects ======================================= The next example uses the Bootstrap JavaScript Library when generating the HTML page. Instead of using functions to generate the HTML elements, we will use objects. .. code-block:: ring #!ring -cgi Load "weblib.ring" Import System.Web Func Main BootStrapWebPage() { div { classname = :container div { classname = :jumbotron H1 { text("Bootstrap Page") } } div { classname = :row for x = 1 to 3 div { classname = "col-sm-4" H3 { html("Welcome to the Ring programming language") } P { html("Using a scripting language is very fun!") } } next } div { classname = :row div { classname = "col-sm-4" Button { classname = "btn btn-info btn-lg" datatoggle= "modal" datatarget = "#myModal" text("Open Large Modal") } } div { classname = "col-sm-4" Button { classname = "btn btn-default btn-lg" text("default") } Button { classname = "btn btn-primary btn-md" text("primary") } Button { classname = "btn btn-sucess btn-sm" text("sucess") } Button { classname = "btn btn-info btn-xs" text("info") } Button { classname = "btn btn-warning" text("warning") } Button { classname = "btn btn-danger" text("danger") } Button { classname = "btn btn-link" text("link") } } div { classname = "col-sm-4" Button { classname = "btn btn-default btn-block" text("default") } Button { classname = "btn btn-primary btn-block" text("primary") } Button { classname = "btn btn-sucess btn-block" text("sucess") } Button { classname = "btn btn-info btn-block" text("info") } Button { classname = "btn btn-warning btn-block" text("warning") } Button { classname = "btn btn-danger btn-block" text("danger") } Button { classname = "btn btn-link btn-block" text("link") } } div { classname = "col-sm-4" div { classname = "btn-group" button { classname="btn btn-primary" text("one") } button { classname="btn btn-primary" text("two") } button { classname="btn btn-primary" text("three") } } } div { classname = "col-sm-4" div { classname = "btn-group btn-group-lg" button { classname="btn btn-primary" text("one") } button { classname="btn btn-primary" text("two") } button { classname="btn btn-primary" text("three") } } } div { classname = "col-sm-4" div { classname = "btn-group-vertical btn-group-lg" button { classname="btn btn-primary" text("one") } button { classname="btn btn-primary" text("two") } button { classname="btn btn-primary" text("three") } } } } div { classname="modal fade" id="myModal" role="dialog" div { classname = "modal-dialog modal-lg" div { classname="modal-content" div { classname="modal-header" button { classname="close" datadismiss="modal" html("×") } h4 { classname="modal-title" text("Modal Header") } } div { classname = "modal-body" p { text("This is a large model.") } } div { classname="modal-footer" button { classname = "btn btn-default" datadismiss="modal" text("close") } } } } } } } Screen Shot: .. image:: ex23.jpg :alt: Bootstrap Page using Objects .. index:: pair: Web Development (CGI Library); CRUD Example using MVC CRUD Example using MVC ====================== The next example uses the weblib.ring & datalib.ring. The datalib.ring contains classes for creating database applications using MVC pattern. In this example we create an object from the SalaryController class then call the Routing method. We define the website variable to contains the basic url of the page. When we create the SalaryModel class from the ModelBase class, the salary table will be opened and the columns data will be defined as attributes in the model class. The SalaryView class create an object from the SalaryLanguageEnglish class to be used for translation. The method AddFuncScript is used to call the form for adding/modifying record data. The method FormViewContent is used to determine the controls in the form when we add or modify a record. .. code-block:: ring #!ring -cgi Load "weblib.ring" Load "datalib.ring" Import System.Web website = "ex24.ring" New SalaryController { Routing() } Class SalaryModel from ModelBase Class SalaryController From ControllerBase Class SalaryView From ViewBase oLanguage = new SalaryLanguageEnglish Func AddFuncScript oPage,oController return oPage.scriptfuncajax("myadd",oController.cMainURL+ oController.cOperation+"=add","mysubpage") Func FormViewContent oController,oTranslation,oPage return [ [ oTranslation.aColumnsTitles[2], "textbox", "name", oController.oModel.Name, oPage.stylewidth("100%") ], [ oTranslation.aColumnsTitles[3], "textbox", "salary", oController.oModel.Salary, oPage.stylewidth("50%") ] ] Class SalaryLanguageEnglish cTitle = "Salary Table" cBack = "back" aColumnsTitles = ["ID","Name","Salary"] cOptions = "Options" cSearch = "Search" comboitems = ["Select Option...","Edit","Delete"] cAddRecord = "Add Record" cEditRecord = "Edit Record" cRecordDeleted = "Record Deleted!" aMovePages = ["First","Prev","Next","Last"] cPage = "Page" cOf = "of" cRecordsCount = "Records Count" cSave = "Save" temp = new page cTextAlign = temp.StyleTextRight() cNoRecords = "No records!" Screen Shot: .. image:: ex24.jpg :alt: Salary Table .. image:: ex24_2.jpg :alt: Salary Table - Search .. index:: pair: Web Development (CGI Library); Users registration and Login Users registration and Login ============================ We have the users classes (Model, View & Controller) to deal with the users data like username & email. The next code is stored in ex25_users.ring .. code-block:: ring Class UsersModel from ModelBase cSearchColumn = "username" Class UsersController From ControllerBase aColumnsNames = ["id","username","email"] Func UpdateRecord oModel.id = aPageVars[cRecID] oModel.updatecolumn("username", aPageVars[:username] ) oModel.updatecolumn("email", aPageVars[:email] ) oView.UpdateView(self) Class UsersView from ViewBase oLanguage = new UsersLanguageEnglish Func AddFuncScript oPage,oController return oPage.scriptfunc("myadd",oPage.scriptredirection("ex26.ring")) Func FormViewContent oController,oTranslation,oPage return [ [oTranslation.aColumnsTitles[2],"textbox","username", oController.oModel.UserName,oPage.stylewidth("100%")], [oTranslation.aColumnsTitles[3],"textbox","email", oController.oModel.Email,oPage.stylewidth("50%")] ] Class UsersLanguageEnglish cTitle = "Users Table" cBack = "back" aColumnsTitles = ["ID","User Name","Email"] cOptions = "Options" cSearch = "Search" comboitems = ["Select Option...","Edit","Delete"] cAddRecord = "Add Record" cEditRecord = "Edit Record" cRecordDeleted = "Record Deleted!" aMovePages = ["First","Prev","Next","Last"] cPage = "Page" cOf = "of" cRecordsCount = "Records Count" cSave = "Save" temp = new page cTextAlign = temp.StyleTextRight() cNoRecords = "No records!" In the file ex25.ring we load ex25_users.ring then create an object from UsersController class. Using the created object, we call the routing method. .. code-block:: ring #!ring -cgi Load "weblib.ring" Load "datalib.ring" Load "ex25_users.ring" Import System.Web website = "ex25.ring" New UsersController { Routing() } Screen Shot: .. image:: ex25.jpg :alt: Users Table See the next code for the registration page .. code-block:: ring #!ring -cgi Load "weblib.ring" Load "datalib.ring" Import System.Web website = "ex26.ring" new page { boxstart() text( "Register") newline() boxend() divstart([:style = stylegradient(6) + stylesize("100%","95%") ]) link([ :url = website, :title = "back" , :style = stylecolor("white")]) newline() divstart([ :style= styledivcenter("500","160") + stylegradient(52) ]) formpost("ex27.ring") tablestart([ :Style = stylemarginleft("2%") + stylemargintop("2%") + stylewidth("90%") ]) rowstart([]) cellstart([:style = stylewidth("20%") + styleheight(30)]) text("User Name") cellend() cellstart([ :style = stylewidth("80%") ]) textbox([:name = "username", :style = stylewidth("100%")]) cellend() rowend() rowstart([]) cellstart([ :Style = styleheight(30)]) text("Password") cellend() cellstart([]) textbox([:name = "password" , :type = "password"]) cellend() rowend() rowstart([]) cellstart([ :style = styleheight(30)]) text("Email") cellend() cellstart([]) textbox([:name = "email" , :style = stylewidth("100%")]) cellend() rowend() rowstart([]) cellstart([ :style = styleheight(30)]) cellend() cellstart([ :style = styleheight(30)]) submit([:value = "Register" ]) cellend() rowend() tableend() formend() divend() divend() } Screen Shot: .. image:: ex26.jpg :alt: Registration Page The Registration response .. code-block:: ring #!ring -cgi Load "weblib.ring" Load "datalib.ring" Load "ex25_users.ring" Import System.Web oUser = new UsersModel oUser.Connect() if oUser.findwith("username",aPageVars["username"]) new page { text("The user name is already registered") } return ok if oUser.findwith("email",aPageVars["email"]) new page { text("This email is already registered") } return ok aPageVars["salt"] = str2hex(RandBytes(32)) aPageVars["pwhash"] = sha256(aPagevars["password"]+aPageVars["salt"]) aPageVars["sessionid"] = str2hex(randbytes(32)) oUser.Insert() new page { cookie("sessionid",aPageVars["sessionid"]) text("New User Created!") newline() text("User Name : " + aPageVars["username"]) newline() } oUser.Disconnect() See the next code for the Login page .. code-block:: ring #!ring -cgi Load "weblib.ring" Load "datalib.ring" Import System.Web website = "ex28.ring" new page { boxstart() text( "Login") newline() boxend() divstart([:style = stylegradient(6) + stylesize("100%","95%") ]) link([ :url = website, :title = "back" , :style = stylecolor("white")]) newline() divstart([ :style= styledivcenter("500","130") + stylegradient(52) ]) formpost("ex29.ring") tablestart([ :Style = stylemarginleft("2%") + stylemargintop("2%") + stylewidth("90%") ]) rowstart([]) cellstart([:style = stylewidth("20%") + styleheight(30)]) text("User Name") cellend() cellstart([ :style = stylewidth("80%") ]) textbox([:name = "username", :style = stylewidth("100%")]) cellend() rowend() rowstart([]) cellstart([ :style = styleheight(30)]) text("Password") cellend() cellstart([]) textbox([:name = "password" , :type = "password"]) cellend() rowend() rowstart([]) cellstart([ :style = styleheight(30) ]) cellend() cellstart([]) submit([:value = "Login" ]) cellend() rowend() tableend() formend() divend() divend() } Screen Shot: .. image:: ex28.jpg :alt: Login Page The response page .. code-block:: ring #!ring -cgi Load "weblib.ring" Load "datalib.ring" Load "ex25_users.ring" Import System.Web oUser = new UsersModel oUser.Connect() lResult = oUser.FindWith("username",aPageVars["username"]) new page { if lResult if sha256(aPagevars["password"]+oUser.Salt) = oUser.pwhash text ("Correct Password!") aPageVars["sessionid"] = str2hex(randbytes(32)) oUser.UpdateColumn("sessionid",aPageVars["sessionid"]) cookie("sessionid",aPageVars["sessionid"]) else text ("Bad password!") ok else text("Bad User Name!") ok } oUser.Disconnect() The next code for checking if the user needs to login or not .. code-block:: ring #!ring -cgi Load "weblib.ring" Load "datalib.ring" Load "ex25_users.ring" Import System.Web oUser = new UsersModel oUser.Connect() lResult = oUser.FindWith("sessionid",aPageVars["sessionid"]) new page { if lResult text("User Name : " + oUser.username ) else text("Please Login First!") ok } oUser.Disconnect() .. index:: pair: Web Development (CGI Library); Database, ModelBase & ControllerBase classes Database, ModelBase & ControllerBase classes ============================================ In this section we will see some code from datalib.ring The next code presents the Database, ModelBase & ControllerBase classes .. code-block:: ring Import System.Web Class Database cServer = "localhost" cUserName = "root" cPassword = "root" cDatabase = "mahdb" Func Connect con = mysql_init() mysql_connect(con, cServer, cUserName, cPassWord,cDatabase) Func Disconnect mysql_close(con) Func Query cQuery mysql_query(con,cQuery) Func QueryResult return mysql_result(con) Func QueryResultWithColumns # return columns names + query result return mysql_result2(con) Func QueryValue aResult = mysql_result(con) if islist(aResult) and len(aResult) >= 1 aResult = aResult[1] if len(aResult) >= 1 return aResult[1] ok ok return 0 Func EscapeString x if isstring(x) return MySQL_Escape_String(con,x) else return MySQL_Escape_String(con,string(x)) ok Private con = NULL Class ModelBase from Database cTableName = "" cSearchColumn = "name" aColumns = [] aQueryResult = [] ID = 0 # set table name from class name classname = lower(classname(self)) if right(classname,5) = :model cTablename = left(classname,len(classname)-5) ok Func Insert cValues = "" for x in aColumns cValues += "'" + EscapeString(aPageVars[x]) + "'," Next cValues = left(cValues,len(cValues)-1) # remove last comma cColumns = "" for x in aColumns cColumns += x + "," next cColumns = left(cColumns,len(cColumns)-1) query("insert into " + cTableName + "("+cColumns+") values (" + cValues + ")" ) Func Update nID cStr = "" for x in aColumns cStr += x + " = '" + EscapeString(aPageVars[x]) + "' , " # the space after comma is necessary Next cStr = left(cStr,len(cStr)-2) query("update " + cTableName + " set " + cStr + " where id = " + nID ) Func UpdateColumn cColumn,cValue query("update " + cTableName + " set " + cColumn + " = '" + EscapeString(cValue) + "' where id = " + self.ID ) Func Count cValue query("SELECT count(*) FROM " + cTableName + " where "+cSearchColumn+" like '" + EscapeString(cValue) + "%'") return queryValue() Func Read nStart,nRecordsPerPage query("SELECT * FROM "+ cTableName+" limit " + EscapeString(nStart) + "," + EscapeString(nRecordsPerPage) ) aQueryResult = queryResult() Func Search cValue,nStart,nRecordsPerPage query("SELECT * FROM "+ cTableName+" where "+cSearchColumn+" like '" + EscapeString(cValue) + "%'" + " limit " + EscapeString(nStart) + "," + EscapeString(nRecordsPerPage) ) aQueryResult = queryResult() Func Find nID query("select * from " + cTableName + " where id = " + EscapeString(nID) ) aResult = queryResult()[1] # move the result from the array to the object attributes ID = nID cCode = "" for x = 2 to len(aResult) cCode += aColumns[x-1] + " = hex2str('" + str2hex(aResult[x]) + "')" + nl next eval(cCode) Func FindWith cColumn,cValue query("select * from " + cTableName + " where "+cColumn+" = '" + EscapeString(cValue) + "'" ) aResult = queryResult() if len(aResult) > 0 aResult = aResult[1] else return 0 ok # move the result from the array to the object attributes ID = aResult[1] cCode = "" for x = 2 to len(aResult) cCode += aColumns[x-1] + " = hex2str('" + str2hex(aResult[x]) + "')" + nl next eval(cCode) return 1 Func Delete ID query("delete from " + cTableName + " where id = " + EscapeString(ID) ) Func Clear cCode = "" for x in aColumns cCode += x + ' = ""' + nl next eval(cCode) Func LoadModel # create the columns array query("SELECT * FROM "+ cTableName + " limit 0,1") aQueryResult = QueryResultWithColumns()[1] for x = 2 to len(aQueryResult) aColumns + lower(trim(aQueryResult[x])) next # create attribute for each column for x in aColumns addattribute(self,x) next Func Connect Super.Connect() if nLoadModel = 0 nLoadModel = 1 LoadModel() ok private nLoadModel = 0 Class ControllerBase nRecordsPerPage = 5 nRecordsCount = 0 nPagesCount = 0 nActivePage = 0 # Dynamic creation of oView = new tablenameView and oModel = new tablename.Model classname = lower(classname(self)) if right(classname,10) = :controller tablename = left(classname,len(classname)-10) cCode = "oView = new " + tablename+"View" + nl cCode += "oModel = new " + tablename+"Model" + nl eval(cCode) oModel.connect() ok cSearchName = "searchname" cPart = "part" cPageError = "The page number is not correct" cLast = "last" cOperation = "operation" cRecID = "recid" aColumnsNames = ["id"] for t in oModel.aColumns aColumnsNames + t next cMainURL = website + "?" func Routing switch aPageVars[cOperation] on NULL showtable() on :add addrecord() on :save saverecord() on :delete deleterecord() on :edit editrecord() on :update updaterecord() off func ShowTable nRecordsCount = oModel.Count( aPageVars[cSearchName] ) nPagesCount = ceil(nRecordsCount / nRecordsPerPage) if aPageVars[cPart] = cLast aPageVars[cPart] = string(nPagesCount) ok nActivePage = number(aPageVars[cPart]) if nActivePage = 0 nActivePage = 1 ok if ( nActivePage > nPagesCount ) and nRecordsCount > 0 ErrorMsg(cPageError) return ok nStart = (nActivePage-1)*nRecordsPerPage if aPageVars[cSearchName] = NULL oModel.Read( nStart,nRecordsPerPage ) else oModel.Search( aPageVars[cSearchName],nStart,nRecordsPerPage ) ok oView.GridView(self) func AddRecord oModel.clear() oView.FormViewAdd(Self,:save,false) # false mean don't include record id func SaveRecord oModel.Insert() oView.SaveView(self) func EditRecord oModel.Find( aPageVars[cRecID] ) oView.FormViewEdit(Self,:update,true) # true mean include record id func UpdateRecord oModel.update( aPageVars[cRecID] ) oView.UpdateView(self) func DeleteRecord oModel.Delete( aPageVars[cRecID] ) oView.DeleteView() func braceend oModel.Disconnect() .. index:: pair: Web Development (CGI Library); WebLib API WebLib API ========== In this section we will see the web library functions, classes and methods. ===================== ============= ===================================================================== Function Parameters Description ===================== ============= ===================================================================== LoadVars None Save the request parameters and cookies to aPageVars List WebPage None Create new object from the WebPage Class BootStrapWebPage None Create new object from the BootStrapWebPage Class HTMLSpecialChars cString Encode Special characters to HTML equivalent Template cFile,oObject Execute Ring Code in cFile after accessing oObject using {} Alert cMessage Generate HTML Web Page that display cMessage using JavaScript Alert() HTML2PDF cString Generate and Display PDF File from HTML String (cString) ===================== ============= ===================================================================== The Package System.Web contains the next classes ===================== ======================================================== Class Name Description ===================== ======================================================== Application Contains methods for Encoding, Decoding, Cookies & More. Page Contains methods to generate HTML pages. ScriptFunctions Contains methods to generate some JavaScript Functions. StyleFunctions Contains methods to generate CSS. PageBuffer Generate HTML Page in memory (don't print the output). HTML2PDF Generate PDF File from HTML code. BootStrapPage Using BootStrap Library. WebPage Generate page using objects for each element. HtmlPage Like WebPage but doesn't print the output to stdout. BootStrapWebPage Generate page using objects, using BootStrap Library. ObjsBase Parent Class for page objects. NewObjectsFunctions Methods to create new objects in the page or element. H1 Wraps HTML H1. H2 Wraps HTML H2. H3 Wraps HTML H3. H4 Wraps HTML H4. H5 Wraps HTML H5. H6 Wraps HTML H6. P Wraps HTML P. Link Wraps HTML link. NewLine Wraps HTML NewLine. Div Wraps HTML Div. Form Wraps HTML Form. Input Wraps HTML Input. TextArea Wraps HTML TextArea. Select Wraps HTML Select. Option Wraps HTML Option. Image Wraps HTML Image. UL Wraps HTML UL. LI Wraps HTML LI. Table Wraps HTML Table. TR Wraps HTML TR. TD Wraps HTML TD. TH Wraps HTML TH. Audio Wraps HTML Audio. Video Wraps HTML Video. Nav Wraps HTML Nav. Span Wraps HTML Span. Button Wraps HTML Button. ===================== ======================================================== .. index:: pair: Web Development (CGI Library); Application Class Application Class ================= ===================== ======================================= ===================================================================== Method Parameters Description ===================== ======================================= ===================================================================== DecodeString cString Decode request parameters Decode cString Decode multipart/form-data GetFileName aArray,cVar Get File Name in aArray using cVar SetCookie name,value,expires,path,domain,secure Set Cookie Cookie name,value Set Cookie using name and value only GetCookies None Get Cookies URLEncode cString URL Encode ScriptLibs None Add JavaScript Libraries like BootStrap Print None Print Page Content Style cStyle Add cStyle to page CSS content StartHTML None Add HTTP Header to page content ===================== ======================================= ===================================================================== The method DecodeString is used to get HTTP request parameters. The methods Decode and GetFileName are used for uploading files. The methods SetCookie, Cookie & GetCookies are used for adding and reading cookies. The methods StartHTML, ScriptsLibs, Style & Print are used for page structure and JS/CSS support. The method URLEncode is used to encode a URL to be used in HTML pages. .. index:: pair: Web Development (CGI Library); Page Class Page Class ========== ===================== ======================================= ===================================================================== Method Parameters Description ===================== ======================================= ===================================================================== text x add HTMLSpecialChars(x) to page content (accept strings and numbers) html cString add html code to page content h1 x add x to page content between

and

h2 x add x to page content between

and

h3 x add x to page content between

and

h4 x add x to page content between

and

h5 x add x to page content between
and
h6 x add x to page content between
and
p aPara HTML

, uses aPara List as Hash to get attributes NewLine None add
to page content AddAttributes aPara Convert aPara list as hash to HTML element attributes Link aPara HTML and , uses aPara List as Hash to get attributes Image aPara HTML , uses aPara List as Hash to get attributes Button aPara HTML , uses aPara List as Hash to get attributes ButtonLink aPara HTML , uses link attribute to navigate to link Textbox aPara HTML , uses aPara List as Hash to get attributes Editbox aPara HTML , uses aPara to get attributes Combobox aPara HTML , uses items attribute for