App Source for stock-trader-game by original-demo

The italicised code is automatically inserted into the code to allow it to run in The LiveCode Lab with the Run Time Library (RTL). The RTL source is at the bottom of the page.

index.lc

<?lc
-- generated code
require "../../wasRTL.lc"
wasInitialize "stock-trader-game"
-- end generated code

/*
***** BEGIN LICENSE BLOCK *****

Stock Trader Game, version: 1.0.4
Copyright (c) 2014 Scott McDonald.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

See here for details: http://www.gnu.org/licenses/gpl-3.0.html

Author: Scott McDonald.
Website: http://thelivecodelab.com
Email: scott@thelivecodelab.com
Fax: +612-8580-5726

***** END LICENSE BLOCK *****
*/

require "trader-fns.lc"
require "trader-login.lc"

put empty into dbID
put empty into prompt
if not validLogin(dbID, prompt, userName, userToken) then
wasSetTemplate "trader-template-login"
wasSetActiveArea "rightcontent"

if prompt is not empty then wasPutP prompt
wasPut "<form action='^wasindex.lc' method='POST'>"
wasPut "<table><tbody>"
wasPut "<tr><td>Player Name:</td><td><input type='text' name='name' value='^1' /></td></tr>",$_POST["name"]
wasPut "<tr><td>Password:</td><td><input type='password' name='password' value='^1' /></td></tr>",$_POST["password"]
wasPut "<tr><td></td><td><input type='submit' name='butnLogin' value=' Login ' /></td></tr>"
wasPut "<tr><td></td><td>Don\'t have a login?<br /><a href='trader-register.lc'>Register Here</a></td></tr>"
wasPut "</tbody></table>"
wasPut "</form>"
else
wasSetTemplate "trader-template"
wasSetActiveArea "leftcontent"

put "AAPL,GOOGL,IBM,INTC,MSFT" into sStockCodes
put "Apple,Google,IBM,Intel,Microsoft" into sCompanyNames
put 86400 into sTradeInterval -- number of seconds in day

-- get variables
loadVars sTrendLength,sTrendSlope,sTrendUpCounter,sTrendDownCounter,sTrendUpStock,sTrendDownStock
loadStockHistory sStockHistory
put convertLineToArray(item 2 to 6 of line 1 of sStockHistory,sStockCodes) into sValueArray

-- if necessary, update stock prices for new day
put false into sHistoryUpdated
repeat while item 1 of sStockHistory + sTradeInterval < the seconds
   updateStockHistory sStockCodes,sTradeInterval,sStockHistory,sValueArray,sTrendLength,sTrendSlope,sTrendUpCounter,sTrendDownCounter,sTrendUpStock,sTrendDownStock
   put true into sHistoryUpdated
end repeat
if sHistoryUpdated then
   storeStockHistory sStockHistory
   storeVars sTrendLength,sTrendSlope,sTrendUpCounter,sTrendDownCounter,sTrendUpStock,sTrendDownStock
   updateUserAssets dbID,sStockCodes,sValueArray
end if
put item 1 of sStockHistory into sLastUpdateTime

-- load user data
put "SELECT trade_time,cash,total_assets,holding_aapl,holding_googl,holding_ibm,holding_intc,holding_msft FROM stockuser WHERE user_name = '^1'" into sqlQuery
put subText(sqlQuery, userName) into sqlQuery
put revDataFromQuery(comma,cr,dbID,sqlQuery) into buffer
put item 1 of buffer into sPrevTradeTime
put item 2 of buffer into sCash
put item 3 of buffer into sTotalAssets
put convertLineToArray(item 4 to 8 of buffer,sStockCodes) into sHoldingArray

put "You can now trade by dollar values. For example, entering <em>$2000</em> will buy or sell two thousand dollars worth of stock." into sPrompt
if $_POST["butnTrade"] is not empty then
   put ValidTrades(sStockCodes,sValueArray,sCash,sHoldingArray,sTradeAmount) into sPrompt
   if sPrompt is empty then
     MakeTrades sStockCodes,sValueArray,sTradeAmount,sCash,sHoldingArray
     put sCash + CalculateStockAssets(sStockCodes,sValueArray,sHoldingArray) into sTotalAssets
     put "UPDATE stockuser SET trade_time = ^1,cash = ^2,total_assets = ^3,holding_aapl = ^4,holding_googl = ^5,holding_ibm = ^6,holding_intc = ^7,holding_msft = ^8 WHERE user_name = '^9'" into sqlQuery
     put subText(sqlQuery,sLastUpdateTime,sCash,sTotalAssets,sHoldingArray["AAPL"],sHoldingArray["GOOGL"],sHoldingArray["IBM"],sHoldingArray["INTC"],sHoldingArray["MSFT"],userName) into sqlQuery
     revExecuteSQL dbID,sqlQuery
     put "Trades successful." into sPrompt
   end if
end if

-- summary table
wasPut "<h3>Total Wealth: $^1</h3>",insertDecimal(sTotalAssets)
wasPut "<table><tbody>"
wasPut "<tr><td>Cash:</td><td style='text-align:right;'>$^1</td><td></td></tr>",insertDecimal(sCash)
wasPut "<tr><td>Stock Assets:</td><td style='text-align:right;'>$^1</td><td><em>The stock prices update in about ^2</em>.</td></tr>",insertDecimal(sTotalAssets - sCash),nextTradePrompt(sLastUpdateTime,sTradeInterval)
wasPut "</tbody></table>"

-- trading table
wasPut "<h3>Trading Console</h3>"
wasPut "<form action='^wasindex.lc' method='POST'>"
wasPut "<input type='hidden' name='username' value='^1' />",username
wasPut "<input type='hidden' name='usertoken' value='^1' />",usertoken
wasPut "<table><tbody>"
wasPut "<tr>"
wasPut "<td><strong>Buy</strong></td><td><strong>Sell</strong></td><td style='text-align: left;'><strong>Amount</strong></td><td><strong>Company</strong></td><td><strong>Price</strong></td><td><strong>Holding</strong></td><td><strong>Value</strong></td><td><strong>Change</strong></td>",loopStockCode
wasPut "</tr>"

put convertLineToArray(item 2 to 6 of line 2 of sStockHistory,sStockCodes) into sPrevValueArray

put 1 into loopIndex
repeat for each item loopStockCode in sStockCodes
   wasPut "<tr>"
  
   wasPut "<td><input type='radio' name='radiAction^1' value='buy' ^2 /></td>",loopStockCode,condText($_POST["radiAction" & loopStockCode] = "buy","checked","")
   wasPut "<td><input type='radio' name='radiAction^1' value='sell' ^2 /></td>",loopStockCode,condText($_POST["radiAction" & loopStockCode] = "sell","checked","")
   wasPut "<td><input type='text' name='amount^1' value='^2' style='width: 8em;' /></td>",loopStockCode,defaultText($_POST["amount" & loopStockCode],0)
   wasPut "<td class='lefttext'>^1</td>",item loopIndex of sCompanyNames
   wasPut "<td>$^1</td>",insertDecimal(sValueArray[loopStockCode])
   wasPut "<td>^1</td>",sHoldingArray[loopStockCode]
   wasPut "<td>$^1</td>",insertDecimal(sValueArray[loopStockCode] * sHoldingArray[loopStockCode])
   wasPut "<td>^1</td>",insertDecimal(sValueArray[loopStockCode] - sPrevValueArray[loopStockCode])
  
   wasPut "</tr>"
   add 1 to loopIndex
end repeat
wasPut "<tr>"
wasPut "<td colspan='2'></td>"

wasPut "<td class='lefttext'><input type='submit' name='butnTrade' value=' Make Trades ' style='width: 8em;' /></td>"

wasPut "<td colspan='5' style='text-align:left;'><small>NEWS: Trading is now free, the brokerage fee of 1% is now waived.</small></td>"
wasPut "</tr>"
wasPut "</tbody></table>"

if sPrompt is not empty then
   wasPut "<p style='background-color: #EEE11E;margin: 0.25em 2em 0 0'>&nbsp;^1</p>",sPrompt
end if

wasPut "</form>"

-- price table
wasPut "<h3>Price History</h3>"
wasPut "<table class='pricetable'><tbody>"
wasPut "<tr class='priceheading'>"
wasPut "<td>Date</td><td>Apple</td><td>Google</td><td>IBM</td><td>Intel</td><td>Microsoft</td>"
wasPut "</tr>"

repeat with loopIndex = 1 to 7
   put line loopIndex of sStockHistory into stockValues
   put line loopIndex+1 of sStockHistory into prevStockValues
   wasPut "<tr>"
  
   put item 1 of stockValues into buffer
   convert buffer from seconds to short date
  
   wasPut "<td>^1</td>",buffer
   repeat with loopInner = 2 to 6
     wasPut "<td style='color:#^1'>$^2</td>",condText(item loopInner of stockValues < item loopInner of prevStockValues,"FF0000","007F0E"),insertDecimal(item loopInner of stockValues)
   end repeat
  
   wasPut "</tr>"
end repeat
wasPut "</tbody></table>"

-- top trader table
wasSetActiveArea "rightcontent"
put "SELECT user_name,total_assets FROM stockuser ORDER BY total_assets DESC" into sqlQuery
put revDataFromQuery(comma,cr,dbID,sqlQuery) into buffer
if item 1 of buffer <> "revdberr" then
   wasPut "<h3>Top Traders</h3>"
   wasPut "<table><tbody>"
   -- table heading
   wasPut "<tr class='topheading'>"
   wasPut "<td style='color:#000000;'>Rank</td><td style='color:#000000;'>Assets</td><td style='color:#000000;'>Trader</td>"
   wasPut "</tr>"
   put 1 into index
   put false into foundUser
   repeat for each line loopLine in buffer
     put item 1 of loopLine into loopUserName
     if index < 21 then
      if loopUserName = userName then
       wasPut "<tr style='color:#12EAF3;'><td>^1</td><td>$^2</td><td>^3</td></tr>",index,insertCommas(item 2 of loopLine),loopUserName
       put true into foundUser
      else
       wasPut "<tr><td>^1</td><td>$^2</td><td>^3</td></tr>",index,insertCommas(item 2 of loopLine),loopUserName
      end if
     else
      if not foundUser then
       if loopUserName = userName then
         if index > 21 then wasPut "<tr><td></td><td></td><td></td></tr>"
         wasPut "<tr style='color:#12EAF3;'><td>^1</td><td>$^2</td><td>^3</td></tr>",index,insertCommas(item 2 of loopLine),loopUserName
         exit repeat
       end if    
      end if
     end if
     add 1 to index
   end repeat
   wasPut "</tbody></table>"
   wasPutP "Number of players: " & the number of lines in buffer
end if
end if

if dbID is not empty then revCloseDatabase dbID


/*

-- this query was used to create the database table

put "CREATE TABLE stockuser( " \
   & "user_name VARCHAR(16), " \
   & "user_password VARCHAR(40), " \
   & "user_token INT, " \
   & "trade_time INT, " \
   & "cash BIGINT, " \
   & "total_assets BIGINT, " \
   & "holding_aapl INTEGER, " \
   & "holding_googl INTEGER, " \
   & "holding_ibm INTEGER, " \
   & "holding_intc INTEGER, " \
   & "holding_msft INTEGER, " \
   & "PRIMARY KEY(user_name));" \
   into sqlQuery

*/

-- generated code
wasFinalize
-- end generated code
?>

trader-fns.lc

<?lc

/*
***** BEGIN LICENSE BLOCK *****

Stock Trader Game: trader-fns.lc
Copyright (c) 2014 Scott McDonald.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

See here for details: http://www.gnu.org/licenses/gpl-3.0.html

Author: Scott McDonald.
Website: http://thelivecodelab.com
Email: scott@thelivecodelab.com
Fax: +612-8580-5726

***** END LICENSE BLOCK *****
*/
-- some general purpose handlers

function alphaNumeric pText
local libValid
put pText is not empty into libValid
repeat for each char loopCh in pText
   if loopCh is not among the chars of "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" then
     put false into libValid
     exit repeat
   end if
end repeat
return libValid
end alphaNumeric

function passwordHash pPassword
get binaryDecode("H*",sha1Digest(pPassword),pPassword)
return pPassword
end passwordHash

function subText pText
repeat with loopIndex = the paramCount down to 2
   replace "^" & loopIndex - 1 with param(loopIndex) in pText
end repeat
return pText
end subText

function defaultText pText,pDefault
if pText is empty then
   return pDefault
else
   return pText
end if
end defaultText

function condText pCondition,pTrue,pFalse
if pCondition then
   return pTrue
else
   return pFalse
end if
end condText

-- handlers specifically for Stock Trader

command loadVars @pTrendLength,@pTrendSlope,@pTrendUpCounter,@pTrendDownCounter,@pTrendUpStock,@pTrendDownStock
local libBuffer
put URL("file:stockvars.cfg") into libBuffer
put line 1 of libBuffer into pTrendLength
put line 2 of libBuffer into pTrendSlope
put line 3 of libBuffer into pTrendUpCounter
put line 4 of libBuffer into pTrendDownCounter
put line 5 of libBuffer into pTrendUpStock
put line 6 of libBuffer into pTrendDownStock
if pTrendLength is empty then
   put Random(5) into pTrendLength
   put Trunc(Random(20) - 10)/1000 into pTrendSlope
   put 0 into pTrendUpCounter
   put 0 into pTrendDownCounter
   put empty into pTrendUpStock
   put empty into pTrendDownStock
end if
end loadVars

command storeVars
local libBuffer = ""
repeat with loopIndex = 1 to the paramCount
   put param(loopIndex) & cr after libBuffer
end repeat
put libBuffer into URL("file:stockvars.cfg")
end storeVars

command loadStockHistory @pStockHistory
put URL("file:stockhistory.cfg") into pStockHistory
if pStockHistory is empty then
   put the seconds - 100,10000,8500,15000,14000,11000 into pStockHistory
end if
end loadStockHistory

command storeStockHistory pStockHistory
put pStockHistory into URL("file:stockhistory.cfg")
end storeStockHistory

command updateStockHistory pStockCodes,pTradeInterval,@pStockHistory,@pValueArray,@pTrendLength,@pTrendSlope,@pTrendUpCounter,@pTrendDownCounter,@pTrendUpStock,@pTrendDownStock
put pStockCodes into randomStockList
if pTrendUpCounter > 0 then replace pTrendUpStock with empty in randomStockList
if pTrendDownCounter > 0 then replace pTrendDownStock with empty in randomStockList
if pTrendUpCounter = 0 then
   put item 1 of pStockCodes into highestStock
   repeat for each item loopStockCode in pStockCodes
     if pValueArray[loopStockCode] > pValueArray[highestStock] then
      put loopStockCode into highestStock
     end if
   end repeat
   put any item of randomStockList into pTrendUpStock
   repeat while (pTrendUpStock = highestStock) or (pTrendUpStock is empty)
     put any item of randomStockList into pTrendUpStock
   end repeat
   replace pTrendUpStock with empty in randomStockList
   put 1 + random(4) into pTrendUpCounter
end if
if pTrendDownCounter = 0 then
   put item 1 of pStockCodes into lowestStock
   repeat for each item loopStockCode in pStockCodes
     if pValueArray[loopStockCode] < pValueArray[lowestStock] then
      put loopStockCode into lowestStock
     end if
   end repeat
   replace lowestStock with empty in randomStockList
   put any item of randomStockList into pTrendDownStock
   repeat while pTrendDownStock is empty
     put any item of randomStockList into pTrendDownStock
   end repeat
   replace pTrendDownStock with empty in randomStockList
   put 1 + random(4) into pTrendDownCounter
end if
subtract 1 from pTrendUpCounter
subtract 1 from pTrendDownCounter
put item 1 of pStockHistory + pTradeInterval into newStockLine
repeat for each item loopStockCode in pStockCodes
   put random(100) into overallFactor
   put 0 into trendingFactor
   if loopStockCode = pTrendUpStock then put 250 + Random(250) into trendingFactor
   if loopStockCode = pTrendDownStock then put - 250 - Random(250) into trendingFactor
   put Trunc(pTrendSlope * pValueArray[loopStockCode]) + overallFactor + Trunc(3 - Random(6)) + trendingFactor into stockDelta
   add round(stockDelta) to pValueArray[loopStockCode]
   put 1000 + Random(500) into stockFloor
   if pValueArray[loopStockCode] < stockFloor then put stockFloor into pValueArray[loopStockCode]
   put comma & pValueArray[loopStockCode] after newStockLine
end repeat
subtract 1 from pTrendLength
if pTrendLength = 0 then
   put Trunc(Random(20) - 10)/1000 into pTrendSlope
   put 1 + Random(5) into pTrendLength
end if
put newStockLine & cr before pStockHistory
end updateStockHistory

command updateUserAssets pDBID,pStockCodes,pValueArray
put "UPDATE stockuser SET total_assets = cash + holding_aapl * ^1 + holding_googl * ^2 + holding_ibm * ^3 + holding_intc * ^4 + holding_msft * ^5;" into sqlQuery
put subText(sqlQuery,pValueArray[item 1 of pStockCodes],pValueArray[item 2 of pStockCodes],pValueArray[item 3 of pStockCodes],pValueArray[item 4 of pStockCodes],pValueArray[item 5 of pStockCodes]) into sqlQuery
revExecuteSQL pDBID,sqlQuery
end updateUserAssets

function ValidTrades pStockCodes,pStockValues,pCash,pStockHolding,@pTradeAmount
put empty into libPrompt
put 0 into libTotal
-- make sure all numbers
repeat for each item loopStockCode in pStockCodes
   put $_POST["amount" & loopStockCode] into loopAmount
   if first char of loopAmount = "$" then
      delete first char of loopAmount
     if (loopAmount is not a number) or (loopAmount < 0) then
      put "Each dollar amount must be a positive number without commas." into libPrompt
      exit repeat
     end if
     put 100* loopAmount div pStockValues[loopStockCode] into loopAmount
   end if
   if (loopAmount is not an integer) or (loopAmount < 0) then
     put "Each amount must be zero, a whole positive number or a dollar value." into libPrompt
     exit repeat
   end if
   if loopAmount is an integer then
     if (loopAmount > 0) and ($_POST["radiAction" & loopStockCode] is empty) then
      put "Choose whether to buy or sell." into libPrompt
      exit repeat
     else
      if loopAmount > 0 then
       add loopAmount to libTotal
      end if
     end if
   end if
   put loopAmount into pTradeAmount[loopStockCode]
end repeat
if (libPrompt is empty) and (libTotal = 0) then
   put "Enter the amounts you want to trade." into libPrompt
end if
if libPrompt is empty then
   -- get amount of pCash after selling
   repeat for each item loopStockCode in pStockCodes
     if $_POST["radiAction" & loopStockCode] = "sell" then
      add pTradeAmount[loopStockCode] * pStockValues[loopStockCode] to pCash
     end if
   end repeat
   -- then check if have enough to do buying
   repeat for each item loopStockCode in pStockCodes
     if $_POST["radiAction" & loopStockCode] = "buy" then
      subtract pTradeAmount[loopStockCode] * pStockValues[loopStockCode] from pCash
      if pCash < 0 then
       put "You don't have enough cash to buy this much stock." into libPrompt
      end if
     end if
   end repeat
end if
if libPrompt is empty then
   repeat for each item loopStockCode in pStockCodes
     if $_POST["radiAction" & loopStockCode] = "sell" then
      if pTradeAmount[loopStockCode] > pStockHolding[loopStockCode] then
       put "You don't have that much stock to sell." into libPrompt
      end if
     end if
   end repeat
end if
return libPrompt
end ValidTrades

command MakeTrades pStockCodes,pStockValues,pTradeAmount,@pCash,@pStockHolding
repeat for each item loopStockCode in pStockCodes
   if $_POST["radiAction" & loopStockCode] = "sell" then
     add pTradeAmount[loopStockCode]* pStockValues[loopStockCode] to pCash
     subtract pTradeAmount[loopStockCode] from pStockHolding[loopStockCode]
   end if
   if $_POST["radiAction" & loopStockCode] = "buy" then
     subtract pTradeAmount[loopStockCode] * pStockValues[loopStockCode] from pCash
     add pTradeAmount[loopStockCode] to pStockHolding[loopStockCode]
   end if
end repeat
put Round(pCash) into pCash
end MakeTrades

function CalculateStockAssets pStockCodes,pStockValues,pStockHolding
local libTotal = 0
repeat for each item loopStockCode in pStockCodes
   add pStockValues[loopStockCode] * pStockHolding[loopStockCode] to libTotal
end repeat
return round(libTotal)
end CalculateStockAssets

function nextTradePrompt pLastUpdateTime,pTradeInterval
local libSeconds,libMinutes
put pLastUpdateTime + pTradeInterval - the seconds into libSeconds
put libSeconds div 60 into libMinutes
if libMinutes > 120 then return round(libMinutes / 60) & " hours."
if libMinutes > 0 then return libMinutes & " minutes."
return libSeconds & " seconds."
end nextTradePrompt

function convertLineToArray pLine,pKeys
local libBuffer = ""
local libIndex = 1
repeat for each item loopItem in pLine
   put loopItem into libBuffer[item libIndex of pKeys]
   add 1 to libIndex
end repeat
return libBuffer
end convertLineToArray

function insertDecimal pText
local libIndex,minusSign
if first char of pText = "-" then
   put "-" into minusSign
   delete first char of pText
else
   put empty into minusSign
end if
repeat 3 - length(pText) times
   put "0" before pText
end repeat
put "." before char -2 of pText
put length(pText) - 5 into libIndex
repeat while libIndex > 1
   put comma before char libIndex of pText
   subtract 3 from libIndex
end repeat
return minusSign & pText
end insertDecimal

function insertCommas pText
local libIndex
put Round(pText / 100) into pText
put length(pText) - 2 into libIndex
repeat while libIndex > 1
   put comma before char libIndex of pText
   subtract 3 from libIndex
end repeat
return pText
end insertCommas

?>

trader-register.lc

<?lc

/*
***** BEGIN LICENSE BLOCK *****

Stock Trader Game: trader-register.lc
Copyright (c) 2014 Scott McDonald.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

See here for details: http://www.gnu.org/licenses/gpl-3.0.html

Author: Scott McDonald.
Website: http://thelivecodelab.com
Email: scott@thelivecodelab.com
Fax: +612-8580-5726

***** END LICENSE BLOCK *****
*/
require "trader-fns.lc"

wasSetTemplate "trader-template-register"
wasSetActiveArea "content",empty

put false into libRegistered
if $_POST["butnRegister"] is not empty then
put empty into libPrompt
if (libPrompt is empty) and (($_POST["name"] is empty) or ($_POST["password"] is empty))then put "Please enter a name and password." into libPrompt
if (libPrompt is empty) and not alphaNumeric($_POST["name"]) then put "Please use only letters and numbers for your player name." into libPrompt
if (libPrompt is empty) and (length($_POST["name"]) > 16) then put "Please use 16 characters of less for your player name." into libPrompt
if (libPrompt is empty) and not alphaNumeric($_POST["password"]) then put "Please use only letters and numbers for your password." into libPrompt
if (libPrompt is empty) and (length($_POST["password"]) < 5) then put "Please use more than 4 characters for your password." into libPrompt
if libPrompt is empty then
   put revOpenDatabase("mysql","localhost",<hidden>,<hidden>,<hidden>,,"/var/lib/mysql/mysql.sock") into dbID
   put "SELECT user_name FROM stockuser WHERE user_name = '^1'" into sqlQuery
   put subText(sqlQuery,$_POST["name"]) into sqlQuery
   put revDataFromQuery(comma,cr,dbID,sqlQuery) into buffer
   if buffer is empty then
     put "INSERT INTO stockuser(user_name,user_password,user_token,trade_time,cash,total_assets,holding_aapl,holding_googl,holding_ibm,holding_intc,holding_msft) VALUES('^1','^2',0,0,1000000,1000000,0,0,0,0,0)" into sqlQuery
     put subText(sqlQuery,$_POST["name"],passwordHash($_POST["password"])) into sqlQuery
     revExecuteSQL dbID,sqlQuery
     wasPutP "Thank you for registering to play Stock Trader."
     wasPutP "Please make a note of your name and password:"
     wasPut "<ul><li>^1</li><li>^2</li></ul>",$_POST["name"],$_POST["password"]
     wasPutP "<small>There is no password recovery, so if you forgot you will lose your progress!</small>"
     put true into libRegistered
   else
     put "That player name is taken, please try another." into libPrompt
   end if
end if
end if
if not libRegistered then
if libPrompt is not empty then wasPutP libPrompt
wasPut "<form action='trader-register.lc' method='POST'>"
wasPut "<table><tbody>"
wasPut "<tr><td>Player Name:</td><td><input type='text' name='name' value='^1' /></td></tr>",$_POST["name"]
wasPut "<tr><td>Password:</td><td><input type='password' name='password' value='^1' /></td></tr>",$_POST["password"]
wasPut "<tr><td></td><td><input type='submit' name='butnRegister' value=' Register ' /></td></tr>"
wasPut "</tbody></table>"
wasPut "</form>"
end if

?>

Note: to maintain security, the database name and password is hidden.

trader-login.lc

<?lc

/*
***** BEGIN LICENSE BLOCK *****

Stock Trader Game: trader-login.lc
Copyright (c) 2014 Scott McDonald.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

See here for details: http://www.gnu.org/licenses/gpl-3.0.html

Author: Scott McDonald.
Website: http://thelivecodelab.com
Email: scott@thelivecodelab.com
Fax: +612-8580-5726

***** END LICENSE BLOCK *****
*/
function validLogin @pDBID,@pPrompt,@pUserName,@pUserToken
put empty into pPrompt
put false into isValid
if ($_POST["username"] is empty) or ($_POST["usertoken"] is empty) then
   if $_POST["butnLogin"] is not empty then
     put "Incorrect name or password, please try again." into pPrompt
     if alphaNumeric($_POST["name"]) and alphaNumeric($_POST["password"]) then
      put revOpenDatabase("mysql","localhost",<hidden>,<hidden>,<hidden>,,"/var/lib/mysql/mysql.sock") into pDBID
      put "SELECT user_password FROM stockuser WHERE user_name = '^1'" into sqlQuery
      put subText(sqlQuery,$_POST["name"]) into sqlQuery
      put revDataFromQuery(comma,cr,pDBID,sqlQuery) into buffer
      if passwordHash($_POST["password"]) = buffer then
       put $_POST["name"] into username
       put random(1000000000) into usertoken
       put "UPDATE stockuser SET user_token = ^1 WHERE user_name = '^2'" into sqlQuery
       put subText(sqlQuery,usertoken,username) into sqlQuery
       revExecuteSQL pDBID,sqlQuery
       put username into pUserName
       put usertoken into pUserToken
       put empty into pPrompt
       put true into isValid
      end if
     end if
   end if
else
   put "Your login has expired, please login again." into pPrompt
   if alphaNumeric($_POST["username"]) and alphaNumeric($_POST["usertoken"]) then
     put revOpenDatabase("mysql","localhost",<hidden>,<hidden>,<hidden>,,"/var/lib/mysql/mysql.sock") into pDBID    
     put "SELECT user_token FROM stockuser WHERE user_name = '^1'" into sqlQuery
     put subText(sqlQuery,$_POST["username"]) into sqlQuery
     put revDataFromQuery(comma,cr,pDBID,sqlQuery) into buffer
     if $_POST["usertoken"] = buffer then
      put $_POST["username"] into pUserName
      put $_POST["usertoken"] into pUserToken
      put empty into pPrompt
      put true into isValid
     end if
   end if
end if
return isValid
end validLogin

?>

Note: to maintain security, the database name and password is hidden.

 

wasRTL.lc

<?lc

/*
***** BEGIN LICENSE BLOCK *****

wasRTL.lc 1.0.0.1
Runtime Library for web apps hosted at The LiveCode Lab.
Copyright (c) 2014 Scott McDonald.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

See here for details: http://www.gnu.org/licenses/gpl-3.0.html

Author: Scott McDonald.
Website: http://thelivecodelab.com
Email: scott@thelivecodelab.com
Fax: +612-8580-5726

***** END LICENSE BLOCK *****
*/


local wasInitCounter
local wasHTMLBuffer,wasPageBuffer,wasAreaBuffer
local wasActiveArea,wasAreaArray,wasAreaAppend
local wasTemplate,wasAppFolder,wasDeveloper

-- The commands below are for common use in your apps.
-- This group is about making it simple for your app
-- to output HTML to the browser.

command wasRaw pText
  put pText after wasHTMLBuffer
end wasRaw

command wasPut pText
  replace "'" with quote in pText
  repeat with wasLoopIndex = the paramCount down to 2
    replace "^" & wasLoopIndex - 1 with param(wasLoopIndex) in pText
  end repeat
  replace "\" & quote with "'" in pText
  if wasActiveArea is empty then
    put pText & cr after wasHTMLBuffer
  else
    put pText & cr after wasAreaBuffer
  end if
end wasPut

command wasPutP pText
  replace "'" with quote in pText
  repeat with wasLoopIndex = the paramCount down to 2
    replace "^" & wasLoopIndex - 1 with param(wasLoopIndex) in pText
  end repeat
  replace "\" & quote with "'" in pText
  if wasActiveArea is empty then
    put "<p>" & pText & cr & "</p>" & cr after wasHTMLBuffer
  else
    put "<p>" & pText & cr & "</p>" & cr after wasAreaBuffer
  end if
end wasPutP

command wasPutBR pText
  replace "'" with quote in pText
  repeat with wasLoopIndex = the paramCount down to 2
    replace "^" & wasLoopIndex - 1 with param(wasLoopIndex) in pText
  end repeat
  replace "\" & quote with "'" in pText
  if wasActiveArea is empty then
    put pText & "<br />" & cr after wasHTMLBuffer
  else
    put pText & "<br />" & cr after wasAreaBuffer
  end if
end wasPutBR

command wasSetTemplate pName
  local wasPath
  put empty into wasTemplate
  put pName into wasPath
  if not (wasPath ends with ".html") then put ".html" after wasPath
  if there is a file wasPath then
    put URL("file:" & wasPath) into wasTemplate
  else
    put "../../wasTemplates/" before wasPath
    if there is a file wasPath then
      put URL("file:" & wasPath) into wasTemplate
    end if
  end if
  if wasTemplate is empty then
    wasPutP "wasSetTemplate: Cannot find template: ^1",pName
  end if
end wasSetTemplate

command wasSetActiveArea pArea
  if wasAreaBuffer is not empty then
    if wasAreaAppend then
      put wasAreaBuffer after wasAreaArray[wasActiveArea]
    else
      put wasAreaBuffer into wasAreaArray[wasActiveArea]
    end if
    put empty into wasAreaBuffer
  end if
  if wasTemplate contains "^" & pArea then
    put pArea into wasActiveArea
    put false into wasAreaAppend
  else
    wasPutP "wasSetActiveArea: Cannot find area: ^1",pArea
  end if
end wasSetActiveArea


command wasSetAppendArea pArea
  if wasAreaBuffer is not empty then
    if wasAreaAppend then
      put wasAreaBuffer after wasAreaArray[wasActiveArea]
    else
      put wasAreaBuffer into wasAreaArray[wasActiveArea]
    end if
    put empty into wasAreaBuffer
  end if
  if wasTemplate contains "^" & pArea then
    put pArea into wasActiveArea
    put true into wasAreaAppend
  else
    wasPutP "wasSetAppendArea: Cannot find area: ^1",pArea
  end if
end wasSetAppendArea


command wasSetAreaText pArea,pText
  put pText into wasAreaArray[pArea]
end wasSetAreaText


-- The commands below are automatically insert into your app.
-- You should not call these in your code.

command wasInitialize pAppFolder
  if wasInitCounter is empty then put 0 into wasInitCounter
  add 1 to wasInitCounter
  if wasInitCounter = 1 then
    put empty into wasTemplate
    put empty into wasActiveArea
    wasHTMLHeader pAppFolder
    put wasHTMLBuffer into wasPageBuffer
    put empty into wasHTMLBuffer
  end if
end wasInitialize

command wasFinalize
  subtract 1 from wasInitCounter
  if wasInitCounter < 1 then
    if wasAreaBuffer is not empty then
      if wasAreaAppend then
        put wasAreaBuffer after wasAreaArray[wasActiveArea]
      else
        put wasAreaBuffer into wasAreaArray[wasActiveArea]
      end if
      put empty into wasAreaBuffer
    end if
    repeat for each key loopArea in wasAreaArray
      replace "^" & loopArea with wasAreaArray[loopArea] in wasTemplate
    end repeat
    put false into doneBody
    if wasHTMLBuffer is not empty then
      if not (wasHTMLBuffer contains "<body") then
        put "<body>" & cr after wasPageBuffer
        put true into doneBody
      end if
      put wasHTMLBuffer after wasPageBuffer
    end if
    if wasTemplate is not empty then
      if not doneBody and not (wasTemplate contains "<body") then
        put "<body>" & cr after wasPageBuffer
        put true into doneBody
      end if
      put wasTemplate after wasPageBuffer
    end if
    if not doneBody and not (wasPageBuffer contains "<body") then
        put "<body>" & cr after wasPageBuffer
        put true into doneBody
      end if
    if not (wasPageBuffer contains "</body>") then put "</body>" & cr after wasPageBuffer
    put "</html>" after wasPageBuffer
    if $_GET["wasdebug"] is not empty then
      if not ((wasPageBuffer contains "<em>Syntax Error</em>") or (wasPageBuffer contains "<em>Security Error</em>")) then
        if wasPageBuffer contains ".lc?" then replace ".lc?" with ".lc" in wasPageBuffer
        replace ".lc" with ".lc?wasdebug=" & $_GET["wasdebug"] & "&" in wasPageBuffer
      end if
      replace "<body>" with "<body>" & cr & "<!-- generated html, not in public apps -->" & cr & "<p><span class='redbuttonlink'><a href='../../appedit.tlcl?wasdebug=" & $_GET["wasdebug"] & "'> Edit App </a></span>&nbsp;&nbsp;" & cr & "<span class='redbuttonlink'><a href='../../appmanager.tlcl?wasdebug=" & $_GET["wasdebug"] & "'> App Manager </a></span>" & cr & "</p>" & cr & "<!-- end generated html -->" & cr in wasPageBuffer
      replace "^wasindex" with "index" in wasPageBuffer
    else
      replace "^wasindex" with "index" in wasPageBuffer
    end if
    if wasDeveloper is not empty then
      replace "^wasuserlogin" with wasDeveloper in wasPageBuffer
      put upper(char 1 of wasDeveloper) into char 1 of wasDeveloper
      replace "^wasusername" with wasDeveloper in wasPageBuffer
    end if
    put wasPageBuffer
  end if
end wasFinalize

command wasHTMLHeader pAppFolder
  put pAppFolder into wasAppFolder
  put URL("file:../" & pAppFolder & ".config") into wasConfig
  put line 4 of wasConfig into wasFlags
  if wasFlags is empty then put 0 into wasFlags
  if (wasFlags bitAND 4) <> 0 then
    wasPut "<!DOCTYPE html>"
  else
    wasPut "<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN' 'http://www.w3.org/TR/html4/loose.dtd'>"
  end if
  wasPut "<html lang='EN' dir='ltr'>"
  wasPut "<head>"
  wasPut "<title>^1</title>",line 2 of wasConfig
  wasPut "<meta http-equiv='content-type' content='text/xml; charset=utf-8' />"
  wasPut "<meta name='generator' content='The LiveCode Lab 1.0.0.0'>"
  put line 6 of wasConfig into wasBuffer
  if wasBuffer is not empty then wasPut "<meta name='description' content='^1'>",wasBuffer
  put line 7 of wasConfig into wasBuffer
  if wasBuffer is not empty then wasPut "<meta name='keywords' content='^1'>",wasBuffer
  put line 8 of wasConfig into wasBuffer
  if wasBuffer is not empty then
    wasPut "<link rel='icon' href='^1' type='image/x-icon'>",wasBuffer
    wasPut "<link rel='shortcut icon' href='^1' type='image/x-icon'>",wasBuffer
  end if
  if (wasFlags bitAND 2) = 0 then wasPut "<meta name='robots' content='noindex,nofollow'>"
  wasPut "<link rel='stylesheet' type='text/css' href='../../wasTemplates/main.css' />"
  wasPut "</head>"
  if $_GET["wasdebug"] is empty then
    if (wasFlags bitAND 1) <> 0 then
      put line 1 of wasConfig into wasDeveloper
      put line 5 of wasConfig into wasCounter
      if wasCounter is empty then put 0 into wasCounter
      put wasCounter + 1 into line 5 of wasConfig
      if there is a file "../../applist.cache" then
        delete file "../../applist.cache"
      end if
    end if
    put the seconds into line 11 of wasConfig
    put wasConfig into URL("file:../" & pAppFolder & ".config")
  else
    put item 1 of $_GET["wasdebug"] into wasDeveloper
  end if
end wasHTMLHeader

function wasDefaultText pText,pDefault
  if pText is empty then
    return pDefault
  else
    return pText
  end if
end wasDefaultText

-- The command below is for handling error conditions.
-- You should not call it from your code.

function wasSubText pText
   replace "'" with quote in pText
  repeat with loopIndex = the paramCount down to 2
    replace "^" & loopIndex - 1 with param(loopIndex) in pText
  end repeat
  replace "\" & quote with "'" in pText
  return pText
end wasSubText

on scriptExecutionError pErrorStack,pFileList
  put empty into wasActiveArea
  set itemDelimiter to slash
  put empty into wasTBuffer
  repeat for each line wasLoopLine in pFileList
    put last item of wasLoopLine & cr after wasTBuffer
  end repeat
  set itemDelimiter to comma
  put wasTBuffer into pFileList
  
  put empty into wasDupFileList
  put "<p class='prompt'><em>Execution Error</em><br />" into wasErrorPrompt
  put URL("file:../../livecode-error-execute-6-5-2.txt") into wasExecuteList
  repeat for each line loopLine in pErrorStack
    switch item 1 of loopLine
      case 471
      case 728
        put line (item 4 of loopLine) of pFileLIst into wasFileName
        if true or not (wasFileName begins with "was") then
          if wasFileName is not among the lines of wasDupFileList then
            if $_GET["wasdebug"] is not empty then
              if wasFileName = "index.lc" then
                put wasSubText("File: <a href='../../appedit.tlcl?name=^1&id=^2&app=^3'><img src='../../images/tlcl-edit16.png' /></a> ^4<br />",item 1 of $_GET["wasdebug"],item 2 of $_GET["wasdebug"],item 3 of $_GET["wasdebug"],wasFileName) after wasErrorPrompt
              else
                put wasSubText("File: <a href='../../moduleedit.tlcl?name=^1&id=^2&app=^3&mod=^4'><img src='../../images/tlcl-edit16.png' /></a> ^4<br />",item 1 of $_GET["wasdebug"],item 2 of $_GET["wasdebug"],item 3 of $_GET["wasdebug"],wasFileName) after wasErrorPrompt
              end if
            else
              put wasSubText("File: ^1<br />",wasFileName) after wasErrorPrompt
            end if
            put wasFileName & cr after wasDupFileList
          end if
        end if
        break
      case 353
        put "Object Name: " & item 4 to -1 of loopLine & "<br />" after wasErrorPrompt
        break
    end switch
  end repeat
  put true into wasTShowError
  put false into wasTHasShownError
  put empty into wasSource
  repeat for each line loopLine in pErrorStack
    switch item 1 of loopLine
      case 471
      case 728
        if wasTShowError and wasTHasShownError then
          put false into wasTShowError
        end if
        break
      case 353
        break
      default
        if wasTShowError then
          put true into wasTHasShownError
          put item 4 of loopLine into wasHint
          if wasHint is not empty then put ", hint: <strong>" & wasHint & "</strong>" into wasHint
          put wasSubText("&nbsp;&mdash;&nbsp;^1<br />",line (item 1 of loopLine) of wasExecuteList) after wasErrorPrompt
          put item 2 of loopLine into wasErrorLine
          if wasErrorLine <> 0 then
            if wasSource is empty then put URL("file:" & last line of wasDupFileList) into wasSource
            put last word of line wasErrorLine in wasSource into wasTLine
            put wasSubText("&nbsp;&mdash;&nbsp;Line: ^1, column: ^2^3<br />",wasTLine,item 3 of loopLine,wasHint) after wasErrorPrompt
          end if
        end if
    end switch
  end repeat
  put "Program terminated.</p>" after wasErrorPrompt
  put wasPageBuffer & "<body>" & cr
  if $_GET["wasdebug"] is not empty then
    put wasSubText("<p><span class='redbuttonlink'><a href='../../appedit.tlcl?wasdebug=^1'> Edit App </a></span>&nbsp;&nbsp;<span class='redbuttonlink'><a href='../../appmanager.tlcl?&wasdebug=^1'> App Manager </a></span></p>", $_GET["wasdebug"]) & cr
  end if
  put wasErrorPrompt
  put "</body></html>"
  exit to top  
end scriptExecutionError



?>