~~NOTOC~~ ~~NOCACHE~~ {{page>css&nodate&noeditbtn&nofooter}} ===== Week 14 — Web apps and 'The Cloud' ===== This week's topic is about creating content for the Web. ==== Evaluation ==== Up to 10 points can be gained towards your final score by completing the **in-class exercises** on Friday. ==== What you will learn from this class ==== * What a 'Web app' is. * How to implement simple Web app. * What a 'cloud app' is. * How to implement simple cloud app. * What the different forms of cloud computing are. * What SaaS, PaaS, and IaaS mean and are. * What virtualisation is and how it can be used. * What the benefits of the cloud are. * What the risks of the cloud are. * How to set up your own 'cloud' services on your own computers. ==== Preparation === This week's preparation is to watch three short videos about Web applications and three short videos about 'The Cloud', and then complete a couple of short exercises to experience some of the fundamental concepts. === Videos ==== Each set of three videos progresses from very simple to more detailed. ** Web Apps ** | What is a Web App? | 1:48 | https://www.youtube.com/watch?v=qt6gSW-uYKI | | What is a web application? | 6:28 | https://www.youtube.com/watch?v=Hv3czsQh8tg | | Web pages, Websites, and Web Applications | 6:36 | https://www.youtube.com/watch?v=ylbQrYhfa18 | ** The Cloud ** | Computer Basics: What Is the Cloud? | 2:31 | https://www.youtube.com/watch?v=4OO77HFcCUs | | What is the cloud? | 3:00 | https://www.youtube.com/watch?v=i9x0UO8MY0g | | The Three Ways to Cloud Compute | 7:09 | https://www.youtube.com/watch?v=SgujaIzkwrE | ==== Notes ==== There are two exercises below. The first shows how to run code in the user's browser. The second shows how to run a program on the server to generate page content dynamically. If you do not want to try the second exercise then you can skip the rest of this section. If you want to try the second exercise then you will need to install a local Web server that can run server-side scripts. The most popular language for that is called PHP. Run the following command to check if you already have PHP installed on your computer: php --version If your shell says "''command not found''" then expand the instructions below to learn how to install it. ++++ Installing PHP | ** MacOS ** should already have PHP installed. If you are sure it is not there, you can install it using [[https://www.macports.org/|MacPorts]] (or [[http://www.finkproject.org/|Fink]] or [[https://github.com/Homebrew/brew|Homebrew]]). ** Linux and WSL ** should have a package containing PHP. Run this command to install it: sudo apt install php php-cgi (Note that it is important to install both ''php'' and ''php-cgi'' //at the same time//.) ** Windows ** users can download a zip file containing PHP from here: https://windows.php.net/download#php-8.0 I recommend the "VS16 x64 Thread Safe" version. (Download just the "Zip" file; you can ignore the "Debug Pack" and "SDK" downloads.) Once downloaded... - In Explorer, right-click on the zip file and select "Extract All..." . - De-select "Show extracted files when complete". - Click "Extract" This will create a directory called something like ''php-8.0.0-Win32-vs16-x64''. Rename that directory to something simple, like ''PHP'', and then move it to somewhere very convenient. For example, the root of your ''C:'' drive would be OK, after which you can test it works using one of these commands: * (from a shell): ''%%/mnt/c/PHP/php.exe --version%%'' * (from a ''Cmd'' window): ''%%C:\PHP\php.exe --version%%'' If you move the ''PHP'' directory to somewhere else, you'll have to modify the path to ''php.exe'' in your commands appropriately. In the rest of the instructions below, you will have to replace the command ''php'' with the full path, e.g., ''C:\PHP\php.exe''. ++++ /** === === https://www.youtube.com/watch?v=J8hzJxb0rpc (4 minutes) * the Web can be used for any activity built around organising or exchanging data * the Web is accessible from computers, smart phones, and even cars **/ ==== Web projects ==== The following two mini-projects illustrate (A) how to run a program in the client Web browser when displaying a page, and (B) how to run a program in the server to generate parts of a Web page dynamically. These techniques are the foundations of Web and cloud apps. === Project A: Create a small 'click counter' Web app that runs in your browser === We have already seen some of the necessary parts for making a small Web app: * making an input element, e.g., a button, * running JavaScript in response to an event. e.g., clicking the button, and * identifying elements by name using the ''id'' property and the ''getElementById()'' JavaScript function. To make a small 'app' such as a click counter requires just a few additional things, which we will investigate soon: * persistent state, i.e., somewhere to store the 'state' of the application, and * a way to modify the content of an element, e.g., the text inside a paragraph (''p''). == 1. Create a file containing just the structure of the web page == Let's begin very simply and create a file containing just the HTML describing the visible structure of the application. (You can call the file anything you like, including "''index.html''".) The structure will have the following parts: * a heading (so we know what the application does), * a paragraph displaying the current value of the counter, which should initially be ''0'', and * a paragraph containing a clickable button that increases the counter. {{14-index-html.png?direct}}

Click counter

0

== 2. Modify the content of the first paragraph when the button is pressed == The text content of a paragraph is stored in the ''innerHTML'' property of the ''p'' element. Assigning a new value to the ''innerHTML'' property of a paragraph will dynamically change what is displayed inside that paragraph. For example, this will remove the old content of a ''p'' whose ''id'' is ''my-paragraph'' and replace it with a 'Welcome' message: document.getElementById('my-paragraph').innerHTML = 'Welcome to some new content!' To run this code whenever a button is clicked, put the code in the ''onclick'' property of the ''button'' element. The first time the button is clicked, the ''0'' that is initially in the paragraph will be replaced by a longer message. Let's add the two things we need which are an ''id'' for the paragraph (we'll call it ''display'')

0

and the ''onclick'' property for the button (containing the code that updates the paragraph's content).

++++ == 3. Increment the counter when the button is clicked == The ''innerHTML'' property of an element can also be read, so we can also store information there. Let's store the value of the counter in the ''innerHTML'' property of the ''display'' paragraph. One of the interesting things about JavaScript is that values can be used very freely. If a string 'looks like' a number then you can treat it as a number (and perform arithmetic on it). This means we can use the string stored in the ''innerHTML'' of the ''display'' paragraph to remember the numeric value of the counter //and// to represent the string that should be displayed in the paragraph. The ''+='' operator will increment its left-hand side by its right-hand side. For example, ''x += 42'' will increment ''x'' by ''42''. Instead of assigning a new string to the ''display'', we'll use the ''+='' operator to add ''1'' to it.

++++ {{14-index-html-1.png?direct}} Well, that //almost// worked! Instead of adding 1 to the numeric value of the count (which is stored as a string), JavaScript converted the ''1'' into a string and then added that to the end of the displayed count. To increment the numeric value of the count we first have to convert the string ''%%"0"%%'' into the integer ''0''. JavaScript 'pro-tip': if you have a string that you know represents a decimal integer then to convert it into an actual integer you can use the 'unary ''+''' operator. So, if ''x'' contains the string ''%%"41"%%'' then x + 1 will be ''%%"411"%%'', whereas +x + 1 will be ''42'', which is exactly the effect we want when incrementing our counter. {{14-index-html-2.png?direct}} Putting a unary ''+'' in front of the left hand side of the binary ''+'' operator makes the counter work properly.

++++ == 4. Tidy up the code == More complex Web apps will, of course, have a //lot// more JavaScript code. The ''script'' element provides a place to put JavaScript code (in a similar way to the ''style'' element providing a place to put CSS code). One advantage of using a ''script'' element is that you can define things like 'helper functions' and global variables to store persistent values. Let's tidy up the code of our Web app in the following ways: * lookup the ''display'' paragraph just once, and remember it in a global variable called ''display'', * create a function that updates the counter value, with a parameter that gives the amount to increment it by, and * use that function in the ''onclick'' action of the button. The first line of this script creates the global variable ''display'' and assigns to it the element whose ''id'' is ''display''. (In other words, the variable will remember the ''p'' paragraph element that is holding and displaying the current counter value.) The last four lines of this script declare a function called ''count'' with one parameter ''amount''. When the function ''count'' is called with a numeric argument it first converts ''display.innerHTML'' to an integer, adds ''amount'' to that integer, and then stores the result back in ''display.innerHTML''. Storing the results back into the ''display.innerHTML'' has the side effect of causing the browser to redraw the changed parts of the screen, thereby showing the updated counter. The final Web app looks like this:

Click counter

0

== Exercises and challenges == **1. ** Does it matter where you put the ''script'' element? What happens if you move it to the start of the ''body''? **2. ** Add a second button that //decrements// the counter. **3. ** Replace the buttons with a row of four buttons labelled ''-10'', ''-1'', ''+1'', and ''+10''. Make the buttons add the appropriate amount to the counter. Add another row containing just one button labelled ''reset'' that resets the counter to ''0'' when it is clicked. **4. ** Explore some more pieces of JavaScript. Maybe start with the functions [[https://www.w3schools.com/jsref/met_win_setinterval.asp|''setInterval'']] and [[https://www.w3schools.com/jsref/met_win_clearinterval.asp|''clearInterval'']] which can be used to call a function regularly, for example, once every second. Use these functions to implement a stop watch with three buttons: "start", "stop", and "clear". === Project B: Create a simple 'text chat' Cloud app that executes on both server and client === Note: to run this example you (or one of your friends) need to have a computer with PHP installed. PHP only needs to be installed on the //server//, so you can still try this example by connecting your browser (the //client//) to the app running on your friend's Web server where PHP is installed. To do this, instead of visiting ''localhost:8000/chat.php'' just replace ''localhost'' with the IP address of your friend's computer. Since the app is 'served' from your friends Web server, there is nothing left for you to do (except maybe //help them// to implement the chat app!). However, if you //did// install PHP on your computer, then please have fun following along with the rest of this project. == 0. Start a Web server that can run server-side scripts == If you are still running the Python Web server, stop it first. Create a directory for your chat project. Change to that directory and start the PHP Web server on port 8000. mkdir WebChat cd WebChat php -S localhost:8000 (If you want your friends to be able to connect to your server from their remote computers, run "''php -S 0.0.0.0:8000''" instead.) == 1. Create a file containing just the structure of the web page == What is the simplest text chat app that you can imagine? Obviously, at the very least, the client would need: * an input field for you to enter a text message to send to the chat, * a button to press to send the message, and * a display area for the previously sent messages to be displayed. {{14-chat-1.png?direct}} It could look something like the window shown on the right. So, just as with the simple counter Web app, let's begin by entering the HTML that we need to display the static structure of the page. Because we will be running some PHP code every time the web page is accessed, we have to use a file name ending in ''.php'' (instead of ''.html''). You can call your file anything you like, but something like ''chat.php'' would be appropriate. Inside a ''.php'' file you can write HTML, including CSS style and JavaScript that runs on the client, exactly like any other Web page. The following HTML will create the basic static structure of the page: PHP Chat

The new elements here are ''textarea'', ''form'', and ''input''. A ''textarea'' creates a box of a given size (rows and columns) that can display and/or allow editing of text. ''input'' creates various kinds of input element according to its ''type'' attribute. A ''text'' ''input'' creates a single-line text box that you can type into. A ''submit'' ''input'' creates a button whose ''value'' attribute can be used to set its label. A ''form'' groups several ''input'' elements together and allows data from those elements to be sent ('posted') back to the server. Within the ''form'', clicking the ''submit'' ''input'' button will cause the ''form'''s data to be posted back to the server. One source of data sent back to the server is the content of any ''text'' ''input'' boxes. (Conveniently, pressing ''Enter'' inside a ''text'' ''input'' box will also post the content of the ''form'' back to the server.) == 2. Add some dynamically generated content to the page == To demonstrate how PHP generates content in the page, let's insert the name of the //server// into the page title. In addition to normal HTML, a ''.php'' file can also contain these two start "''''" tags. Between those tags is PHP code that is run on the //server// before the content of the file is sent back to the client in the response to the HTTP ''GET'' request. The tags and PHP code are removed from the page content, but anything that the PHP code prints while it is running is added to the page content. The following PHP code prints the name of the server: echo gethostname() Adding that code into the content of the ''title'' element, between '''' tags, inserts the server name into the page title every time the client fetches the page. {{14-chat-2.png?direct}} PHP Chat @ <?php echo gethostname() ?> == 3. Make the "send" button upload the text input area to the server == A ''form'' element collects input from one or more of its child ''input'' elements and then sends the data entered into those inputs back to the server when the form is 'submitted'. When the data is sent back, two things happen: the data is included with the HTTP request, and the server responds with a new Web page that will replace the original one in the browser. This allows the server to change the content of the page every time the user submits data. To send the form data back to the server, and also to see that data and confirm the upload worked, we have to do three things: - tell the ''form'' how to reload the page when the submit button is pressed, - tell the ''text'' ''input'' what name it should use to identify its content (the text the user entered) when the form data is sent back to the server, and - insert the uploaded data into the ''textarea'' content as the page is reloading, to show the upload worked. First, add two attributes to the ''form'' to make it reload the page when its data is submitted. The ''method'' attribute says how to send the form data back to the server. ''GET'' and ''POST'' are the usual ways, and we'll use ''POST''. The ''action'' attribute says what URL should be used to reload a 'result' Web page. We will use the original chat app URL. All variable names in PHP begin with a dollar sign "''$''". The PHP variable ''$_PHP_SELF'' contains the URL of the app page.
The ''name'' attribute has been added to the ''text'' ''input'' element. Setting that attribute to ''send'' allows the server to retrieve the content of the ''text'' ''input'' element using the name ''send'' when the form data is uploaded to the server. (I used ''send'' but you can use any name you like, as long as it is consistent between the ''input'' element and the PHP code that retrieves the data.) If you reload the page you should now find that clicking the ''send'' button, or pressing ''Enter'' in the text input field, will cause the page to reload. == 4. Echo the uploaded data in the text area == The input text is currently being thrown away by the server. Let's instead insert that text into the text area, so that we can see the data is being uploaded properly. To do this we will insert some PHP code into the ''textarea'' content. This code has to - retrieve the data from the ''text'' ''input'' that was uploaded along with the page request (under the name ''send''), and - if the uploaded data is not empty, ''echo'' it to provide new content for the ''textarea''. When the page is reloaded the PHP variable ''$_REQUEST'' contains all the information about the request sent by the client, including any data that was uploaded from ''form''s on the page. ''$_REQUEST'' behaves like an array, indexed by the name of the data you want. The data sent from the ''input'' ''text'' is included in the ''$_REQUEST'' array using the name ''send''. (We told the ''form'' element to call that data ''send'', using the ''name'' attribute of the text input.) The server can therefore access that data as ''%%$_REQUEST["send"]%%''. Inside the ''textarea'' we will add some PHP code to retrieves the ''%%$_REQUEST["send"]%%'' data, store it in the variable ''$send'', and then (if it is not empty) ''echo'' it (to make it become the content of the ''textarea'' element).

| {{14-chat-4b.png?direct}} | \_ | {{14-chat-4a.png?direct}} | == 5. Accumulate the chat text in persistent storage on the server == PHP can write to, and read from, files stored on the server. Let's append each line of text sent in ''%%$_REQUEST["send"]%%'' into a 'chat log' file, and then insert the contents of that file into the page as the content of the ''textarea'' element. The effect will be to collect all the text sent to the chat app and echo them all in the display area. The code will have to - add a newline to the end of the uploaded text, - append the line to a 'chat log' file, - get the entire contents of the 'chat log' file, and - ''echo'' the contents of the 'chat log' file to provide the contents of the ''textarea'' element. Let's store the 'chat log' in a file called ''chatlog.txt''. Instead of ''echo''ing the ''$send'' text into the ''textarea'', first (if it is not empty) append a newline (''%%"\n"%%'') to it (using the string concatenation operator "''.''") and then use the function ''file_put_contents'' to append the result to the ''chatlog.txt'' file. Next, let's use ''file_get_contents'' to retrive the entire contents of ''chatlog.txt'' and (if it is not empty) ''echo'' those contents to make them become the content of the ''textarea'' element. {{14-chat-5.png?direct}} We now have a working Web chat app! Your complete app should look like this: PHP Chat @ <?php echo gethostname() ?>

== Excercises and challenges == **1. ** Automatically set the focus to the text input area when the page (re)loads. Currently it is necessary to click in the text input area to begin typing into it. It would be a better user experience if the text input area were automatically focused when the page (re)loads. Let's set the focus to the correct element when the page has finished loading. Similarly to the ''onclick'' attribute for ''button'' elements, you can use the ''onload'' attribute of the ''body'' element to run some JavaScript when the page has finished loading completely. To do this: * give the ''text'' ''input'' element an identifier (e.g, "''text''"), and then * set the ''onload'' property of the ''body'' element to JavaScript that sets focus to the element with the identifier ''text''. The code you need will look something like this: document.getElementById('text').focus() **2. ** Scroll the ''textarea'' element to the bottom when the page is (re)loaded. When the chat ''textarea'' has more lines of content than space to display them, it displays the oldest lines instead of the newest ones. To fix this, you can * give the ''textarea'' element an identifier (e.g., ''chat''), and * scroll the ''chat'' area to the bottom using JavaScript. The JavaScript to scroll a ''textarea'' to the bottom (most recent lines) looks like this: var chat = document.getElementById('chat'); chat.scrollTop = chat.scrollHeight; {{14-chat-6.png?direct}} **3. ** Prepend the time to each message. In PHP you can obtain the time as a string like this: date("H:i:s") If you prepend this to the message (in the same statement that appends the newline character to it) you will get timestamps in the chat. **4. ** Add each participant's name to their chat messages. Add another text input field to the form that contains your name. Automatically include your name at the start of the message. The easiest way to do this is to send your name (in addition to the chat message text) to the server when the form is submitted, include that "name" value both in the message stored in the chat log file, and then also include the same "name" data in the generated page as the ''value'' attribute of the name text input field. This sounds a bit 'circular' but it will work to both include your name in messages and preserve your chosen name across message submissions (page reloads). /**** **5. ** Make the text area auto-updating. Currently the text area only updates when you send a message. Instead use https://www.w3schools.com/html/html5_serversentevents.asp ****/ == Is this a Web app or a cloud app? == Calling this a 'cloud app' is maybe debatable. However, this app does do many of the things a Cloud app would do... * store persistent data entered by the user on the server, * modify what the user sees based on prior input, and * allow multiple users to collaborate simultaneously from multiple remote clients. The server-side data is stored in a simple text file and the server code runs only on one server. If the persistent data were instead stored a distributed database, and if multiple servers cooperated to share the work of handling thousands of simultaneous users, then there would be no question at all that this qualifies as a 'cloud app'. /* syllabus */ /* * Local Variables: * eval: (flyspell-mode) * eval: (ispell-change-dictionary "british") * eval: (flyspell-buffer) * End: */