Session 14 - Server-Side, Part 2
Harvard Extension School
Fall 2022
Course Web Site: https://cscie12.dce.harvard.edu/
Topics
- Announcements
- "Back end" (Server-Side) Web Development
- Server Side Rendering of Content (SSR)
- PHP Example with Courses Database
- Separation of Concerns
- {{Mustache}} Templates
- Improving the Hello! Greeting
- CSR (Client Side Rendering)
- JavaScript Frameworks - Vue, React, Angular, Ember
- Sending Email
- Oh, The Places You'll Go!
- Thank You!
Presentation contains 32 slides
Announcements
- Office Hours - Appointment and Open. Check out the schedule for the upcoming week for office hours -- there are "open / drop-in" times as well as 20 minute scheduled appointments.
- Wednesday, December 14. Final Project Due and Final Project Presentations [Optional]
Final Project Notes and Observations
- Implement only three parts.
- The rest doesn't have to exist
- Use
href="#"
to link to those things that don't exist yet
- File structure organization:
- All of your html files at the top level
- directory/folder for images, styles, and scripts
. |-- index.html |-- hello-harvard.html |-- images | |-- harvard.jpg | `-- world.jpg |-- scripts | `-- map.js `-- styles `-- site.css
- lowercase file names and without spaces
- Better:
my_favorite_teas.html
- Worse:
My Favorite Teas.html
- Better:
- Within your site, use relative URL links.
- NOT relative:
<link rel="stylesheet" href="/Users/david/Desktop/final_project/styles/site.css"/>
- NOT relative:
- Site-wide CSS Stylesheet!
One CSS stylesheet to style all of your HTML pages!
"Back end" (Server-Side) Web Development
Language | Frameworks/Platforms |
---|---|
JavaScript |
"Back-end": Node, Express "Front-end": React, Vue, Angular, Ember |
PHP | Laravel, Symfony, CodeIgniter, CakePHP CMS: WordPress, Drupal, Joomla, Concrete5, GetSimple |
Python | Django, Flask, Zope, Plone |
Go |
CSR or SSR or SSG
- CSR - Client Side Rendering
e.g. JavaScript within web browser makes request for JSON data, then builds the page based on that data - SSR - Server Side Rendering
Web server hands off HTTP request to a program, and the program generates the content - SSG - Static Site Generation
Content is created programmatically at build time, and the static HTML content is served at time of request.
Server Side Rendering of Content (SSR)
- Internal and persistent (e.g. PHP in Apache)
- External and persistent (e.g. FastCGI)
Web Program Examples
Markup or content is embedded within a program; program embedded into markup
first.py - Python
#!/usr/bin/python3
print("Content-type: text/html\n\n")
print("<html><head><title>Hello World!</title></head>")
print("<body><h1>Hello, World!</h1></body></html>")
first.php - PHP
<?php
echo('<html><head><title>First PHP</title></head><body>');
echo('<h1>Hello!</h1>');
echo('</body></html>');
?>
second.php - PHP
second.php
program statements within markup
<?php
$title = "Hello World!";
?>
<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<title><?php echo($title) ?></title>
</head>
<body>
<h1><?php echo($title) ?></h1>
</body>
</html>
A Personal Greeting
<?php
$name = $_GET["name"];
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Greeting Page</title>
</head>
<body>
<h1>Hello, <?php echo($name) ?>!</h1>
</body>
</html>
A Personal Greeting
Without a "name", present the user a form. With a name, provide a greeting.
<?php
$name = $_GET["name"];
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Greeting Page</title>
</head>
<body>
<?php
if ($name) {
echo("<h1>Hello, $name!</h1>");
} else {
echo('<h1><label for="input_name">Enter name:</label></h1>');
echo('<form method="get">');
echo('<input type="text" name="name" id="input_name"/>');
echo('<br /><input type="submit" />');
echo('<br /><input type="reset" />');
}
?>
</body>
</html>
PHP Example with Courses Database
Harvard Extension Course Data
Course Data in a Spreadsheet
Data Table in a Relational Database
RDBMS = Relational Database Management System
- Postgres
- MySQL
- Oracle
- Microsoft SQL Server
Course Data in RDBMS Table
Course data for Faculty of Arts & Sciences is in a mysql database on cscie12students (username: class; database name: coursecatalog)
SQL:
describe ext_courses
Terminal:
cscie12students$ mysql -u class coursecatalog
Welcome to the MySQL monitor. Commands end with ; or \g.
mysql> describe ext_courses;
+----------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+--------------+------+-----+---------+-------+
| academic_year | year | YES | | NULL | |
| term | varchar(32) | YES | | NULL | |
| term_code | int | YES | | NULL | |
| course_code | int | YES | | NULL | |
| course_number | int | YES | | NULL | |
| short_title | text | YES | | NULL | |
| title | text | YES | | NULL | |
| faculty_description | text | YES | | NULL | |
| department_code | varchar(15) | YES | | NULL | |
| department | varchar(200) | YES | | NULL | |
| course_type | varchar(100) | YES | | NULL | |
| credits | varchar(50) | YES | | NULL | |
| credit_undergraduate | int | YES | | NULL | |
| credit_graduate | int | YES | | NULL | |
| url | varchar(300) | YES | | NULL | |
| days_of_week | varchar(100) | YES | | NULL | |
| start_time | varchar(15) | YES | | NULL | |
| end_time | varchar(15) | YES | | NULL | |
| location | varchar(64) | YES | | NULL | |
| notes | text | YES | | NULL | |
| description | text | YES | | NULL | |
+----------------------+--------------+------+-----+---------+-------+
21 rows in set (0.00 sec)
Selecting List of Departments
SQL Input:
select DISTINCT department_code, department from ext_courses
Terminal Output:
mysql> SELECT DISTINCT department_code, department FROM ext_courses ORDER BY department;
+-----------------+--------------------------------------+
| department_code | department |
+-----------------+--------------------------------------+
| AAAS | African and African American Studies |
| ANTH | Anthropology and Archaeology |
| APMA | Applied Mathematics |
| ARAB | Arabic |
| ASTR | Astronomy |
| BIOS | Biological Sciences |
| BIOT | Biotechnology |
| CELT | Celtic Languages and Literatures |
| CHEM | Chemistry |
| CLAS | Classics |
| CSCI | Computer Science |
| CREA | Creative Writing |
| DEVP | Development Practice |
| DGMD | Digital Media |
| DRAM | Dramatic Arts |
| ECON | Economics |
| EDUC | Education |
| ENSC | Engineering Sciences |
| ENGL | English |
| ENVR | Environmental Studies |
| EXPO | Expository Writing |
| FREN | French Language and Literature |
| GERM | German |
| GOVT | Government |
| CGRK | Greek |
| HIST | History |
| HARC | History of Art and Architecture |
| HUMA | Humanities |
| IORP | Industrial-Organizational Psychology |
| ISMT | Information Systems Management |
| ITAL | Italian |
| JAPA | Japanese |
| JOUR | Journalism |
| LATI | Latin |
| LSTU | Legal Studies |
| MGMT | Management |
| MATH | Mathematics |
| MUSE | Museum Studies |
| MUSI | Music |
| NUTR | Nutrition |
| PHIL | Philosophy |
| PHYS | Physics |
| PSYC | Psychology |
| RELI | Religion |
| SSCI | Social Sciences |
| SOCI | Sociology |
| SPAN | Spanish Language and Literature |
| SPCH | Speech |
| STAT | Statistics |
| STAR | Studio Arts and Film |
+-----------------+--------------------------------------+
50 rows in set (0.01 sec)
PHP Script to Connect to Database and Get List of Departments
<?php
// set header for text content
header('Content-type: text/plain');
// use Dotenv to load database info from .env file
// DB_HOST, DB_USER, DB_PW, DB_NAME
require_once('vendor/autoload.php');
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->safeLoad();
// Connecting, selecting database
$mysqli = new mysqli($_ENV['DB_HOST'],$_ENV['DB_USER'],$_ENV['DB_PW'],$_ENV['DB_NAME']);
if ($mysqli->connect_errno) {
echo "Failed to connect to mysql: ".$mysqli->connect_errno." ".$mysqli->connect_error;
}
// Performing SQL query
$query = 'SELECT DISTINCT department, department_code FROM ext_courses ORDER BY department';
$result = $mysqli->query($query);
// iterating through results
while ($row = $result->fetch_assoc()){
echo $row['department_code'];
echo "\t";
echo $row['department'];
echo "\n";
}
?>
Output
Turn this into HTML Output
<?php
// use Dotenv to load database info from .env file
// DB_HOST, DB_USER, DB_PW, DB_NAME
require_once('vendor/autoload.php');
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->safeLoad();
// Connecting, selecting database
$mysqli = new mysqli($_ENV['DB_HOST'],$_ENV['DB_USER'],$_ENV['DB_PW'],$_ENV['DB_NAME']);
if ($mysqli->connect_errno) {
echo "Failed to connect to mysql: ".$mysqli->connect_errno." ".$mysqli->connect_error;
}
// Performing SQL query
$query = <<<ENDQUERY
SELECT
DISTINCT department, department_code
FROM
ext_courses
ORDER BY
department
ENDQUERY;
$result = $mysqli->query($query);
// iterating through results
echo "<ul>\n";
while ($row = $result->fetch_assoc()) {
echo "<li>";
echo $row['department'];
echo "</li>\n";
}
echo "</ul>\n";
// cleanup query result and close connection
$query_result->free();
$mysqli->close();
?>
The entire "departments-simple.php"
<!DOCTYPE html>
<html>
<head>
<title>Departments</title>
<link rel="stylesheet" href="styles/site.css" />
</head>
<body>
<h1>Harvard Extension School</h1>
<h2>Departments</h2>
<?php
// use Dotenv to load database info from .env file
// DB_HOST, DB_USER, DB_PW, DB_NAME
require_once('vendor/autoload.php');
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->safeLoad();
// Connecting, selecting database
$mysqli = new mysqli($_ENV['DB_HOST'],$_ENV['DB_USER'],$_ENV['DB_PW'],$_ENV['DB_NAME']);
if ($mysqli->connect_errno) {
echo "Failed to connect to mysql: ".$mysqli->connect_errno." ".$mysqli->connect_error;
}
// Performing SQL query
$query = <<<ENDQUERY
SELECT
DISTINCT department, department_code
FROM
ext_courses
ORDER BY
department
ENDQUERY;
$result = $mysqli->query($query);
// iterating through results
echo "<ul>\n";
while ($row = $result->fetch_assoc()) {
echo "<li>";
echo $row['department'];
echo "</li>\n";
}
echo "</ul>\n";
// cleanup query result and close connection
$query_result->free();
$mysqli->close();
?>
<footer>
<p>This is a learning example to demonstrate PHP and mysql for the courses CSCI E-12 and CSCI S-12 taught by David Heitmeyer. <br/>
The real <a href="https://courses.dce.harvard.edu/">Harvard Extension School course search</a> is at: <a href="https://courses.dce.harvard.edu/">courses.dce.harvard.edu</a></p>
</footer>
</body>
</html>
Adding another view - Department Course Listings
Create another PHP file that displays course information based upon a department_code parameter.
courses.php
- take a "department_code" parameter and produce alist of courses for that department.
Need to link to to courses.php:
Modify the department listing to include the hyperlink:
// Printing results in HTML
echo "<ul>\n";
while ($row = $result->fetch_assoc()) {
echo "<li>";
echo "<a href=\"courses.php?department_code=$row[department_code]\">"
echo "$row[department]"
echo "</a>";
echo "</li>\n";
}
echo "</ul>\n";
courses.php
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>Harvard Extension Courses</title>
<link rel="stylesheet" href="styles/site.css" type="text/css"/>
</head>
<body>
<h1>Harvard Extension Courses</h1>
<p><a href="departments.php">Return to Department List</a></p>
<?php
// use Dotenv to load database info from .env file
// DB_HOST, DB_USER, DB_PW, DB_NAME
require_once('vendor/autoload.php');
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->safeLoad();
// Connecting, selecting database
$mysqli = new mysqli($_ENV['DB_HOST'],$_ENV['DB_USER'],$_ENV['DB_PW'],$_ENV['DB_NAME']);
if ($mysqli->connect_errno) {
echo "Failed to connect to mysql: ".$mysqli->connect_errno." ".$mysqli->connect_error;
}
$dept_code = $_GET['department_code'];
$sqlescaped_dept_code = $mysqli->real_escape_string($dept_code);
$dept_code_html = htmlentities($dept_code);
?>
<h2>Department - <?php echo $dept_code_html ?></h2>
<?php
// Performing SQL query
$query = <<<ENDQUERY
SELECT
department,
department_code,
course_number,
term,
academic_year,
short_title,
title,
description,
faculty_description
FROM
ext_courses
WHERE
department_code = '$sqlescaped_dept_code'
ORDER BY
department,
course_number,
title
ENDQUERY;
$result = $mysqli->query($query);
// Printing results in HTML
$i = 0;
while ($row = $result->fetch_assoc()) {
// calculate year
$academic_year_display = $row['academic_year'];
if ($row['term'] == 'Spring' or $row['term'] == 'January') {
$academic_year_display += 1 ;
}
$course_content = <<<ENDCONTENT
<section class="course">
<h2 class="abbrev"> $row[short_title] </h2>
<div>
<p class="term">$row[term] $academic_year_display</p>
<p class="title"><strong>$row[title]</strong></p>
<p class="faculty">$row[faculty_description]</p>
<p class="description">$row[description]</p>
</div>
</section>
ENDCONTENT;
echo($course_content);
}
// cleanup query result and close connection
$query_result->free();
$mysqli->close();
?>
<footer>
<p><a href="./">PHP/mysql example list</a></p>
<p>This is a learning example to demonstrate PHP and mysql for the courses CSCI E-12 and CSCI S-12 taught by David Heitmeyer. <br/>
The real <a href="https://courses.dce.harvard.edu/">Harvard Extension School course search</a> is at: <a href="https://courses.dce.harvard.edu/">courses.dce.harvard.edu</a>
</p>
</footer>
</body>
</html>
Separation of Concerns
Separate the data the view using templates!
- PHP code connects to database and does query and gets the data
- Define how to display that data with a template (generic term) -- and in this case, we'll use Mustache templates! Note that Twig is a popular template system to use with PHP.
{{Mustache}} Templates
{{mustache}} is another widely used template system for JavaScript (and other languages!).
Mustache Departments
Mustache Template
PHP
<?php
// Connecting, selecting database
$mysqli = new mysqli('localhost','class','cscie12','coursecatalog');
if ($mysqli->connect_errno) {
echo "Failed to connect to mysql: ".$mysqli->connect_errno." ".$mysqli->connect_error;
}
// Performing SQL query
$query = 'SELECT DISTINCT department, department_code ext_courses ORDER BY department';
$result = $mysqli->query($query);
$i=0;
while ($row = $result->fetch_assoc()) {
$results[$i++] = $row;
}
$template_data['departments'] = $results;
// Process with Mustache Template
include('lib/Mustache.php');
$m = new Mustache;
$template_file = 'mustache_templates/departments.html';
$template_contents = file_get_contents($template_file);
echo $m->render($template_contents, $template_data);
// cleanup query result and close connection
$query_result->free();
$mysqli->close();
?>
Mustache Template
mustache_templates/departments.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Harvard Extension School - Departments</title>
<link rel="stylesheet" href="styles/site.css" />
</head>
<body>
<h1>Harvard Extension School</h1>
<h2>Departments</h2>
<ul>
{{#departments}}
<li>
<a href="mustache-courses.php?department_code={{department_code}}">{{department}}</a>
</li>
{{/departments}}
</ul>
<footer>
<p><a href="./">PHP/mysql example list</a></p>
<p>This is a learning example to demonstrate PHP and mysql for the courses CSCI E-12 and CSCI S-12 taught by David
Heitmeyer. <br />
The real <a href="https://courses.dce.harvard.edu/">Harvard Extension School course search</a> is at: <a
href="https://courses.dce.harvard.edu/">courses.dce.harvard.edu</a>
</p>
</footer>
</body>
</html>
Mustache Courses
<!DOCTYPE html>
<html lang="en">
<head>
<title>Harvard Extension Courses in {{ department_name }}</title>
<link rel="stylesheet" href="styles/site.css" />
<meta charset="UTF-8" />
</head>
<body>
<h1>Harvard Extension Courses in {{ department_name }}</h1>
<p><a href="mustache-dept.php">Return to Department List</a></p>
<h2>{{department_name}}</h2>
<div>
{{#courses}}
<section class="course">
<h2 class="abbrev">{{ short_title }}</h2>
<div>
<p class="term">{{ term }} {{ academic_year_display }}</p>
<p class="title">{{ title }}</p>
<p class="faculty">{{ faculty_description }}</p>
<p class="description">{{{ description }}}</p>
</div>
</section>
{{/courses}}
</div>
<footer>
<p><a href="./">PHP/mysql example list</a></p>
<p>This is a learning example to demonstrate PHP and mysql for the courses CSCI E-12 and CSCI S-12 taught by David
Heitmeyer. <br />
The real <a href="https://courses.dce.harvard.edu/">Harvard Extension School course search</a> is at: <a
href="https://courses.dce.harvard.edu/">courses.dce.harvard.edu</a>
</p>
</footer>
</body>
</html>
Improving the Hello! Greeting
We started with
Without a "name", present the user a form. With a name, provide a greeting.
<?php
$name = $_GET["name"];
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Greeting Page</title>
</head>
<body>
<?php
if ($name) {
echo("<h1>Hello, $name!</h1>");
} else {
echo('<h1><label for="input_name">Enter name:</label></h1>');
echo('<form method="get">');
echo('<input type="text" name="name" id="input_name"/>');
echo('<br /><input type="submit" />');
echo('<br /><input type="reset" />');
}
?>
</body>
</html>
Hello! Greeting, Improved
Three files: one code; two templates
- index.php
- greeting.html
- form.html
index.php
<?php
$name = $_GET["name"];
// figure out which template is needed
if ($name) {
$template_file = 'greeting.html';
} else {
$template_file = 'form.html';
}
$template_contents = file_get_contents($template_file);
$template_data['name'] = $name;
// Process with Mustache Template
include('lib/Mustache.php');
$m = new Mustache;
echo $m->render($template_contents, $template_data);
?>
greeting.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Greeting Page for {{name}}</title>
</head>
<body>
<h1>Hello, {{name}}!</h1>
</body>
</html>
form.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Greeting Page</title>
</head>
<body>
<h1><label for="input_name">Enter name:</label></h1>
<form method="get">
<input type="text" name="name" id="input_name"/>
<br /><input type="submit" />
<br /><input type="reset" />
</body>
</html>
CSR (Client Side Rendering)
Front-end JavaScript + templates and Back-end JSON
Departments
- json-dept.php - PHP script that produces JSON
- departments.html - uses Handlebars
Courses
- json-courses.php?department_code=CHEM - PHP script that produces JSON
- courses.html?department_code=CHEM - uses Handlebars
JSON PHP data
<?php
/// use Dotenv to load database info .env file
// DB_HOST, DB_USER, DB_PW, DB_NAME
require_once('vendor/autoload.php');
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->safeLoad();
// Connecting, selecting database
$mysqli = new mysqli($_ENV['DB_HOST'],$_ENV['DB_USER'],$_ENV['DB_PW'],$_ENV['DB_NAME']);
if ($mysqli->connect_errno) {
echo "Failed to connect to mysql: ".$mysqli->connect_errno." ".$mysqli->connect_error;
}
$dept_code = $_GET['department_code'];
$sqlescaped_dept_code = $mysqli->real_escape_string($dept_code);
// Performing SQL query
$query = <<<ENDQUERY
SELECT
department,
department_code,
course_number,
term,
academic_year,
short_title,
title,
description,
faculty_description
ext_courses
WHERE
department_code = '$sqlescaped_dept_code'
ORDER BY
department,
course_number,
title
ENDQUERY;
$query_result = $mysqli->query($query);
$i = 0;
while ($row = $query_result->fetch_assoc()) {
// calculate year
$academic_year_display = $row['academic_year'];
if ($row['term'] == 'Spring' or $row['term'] == 'January') {
$academic_year_display += 1 ;
}
$row['academic_year_display'] = $academic_year_display;
$results[$i++] = $row;
}
$template_data['courses'] = $results;
$template_data['department_name'] = $dept_code;
header('Content-type: application/json');
echo json_encode($template_data);
// cleanup query result and close connection
$query_result->free();
$mysqli->close();
?>
Front-end courses
For example: CSCI courses (courses.html?department_code=CSCI
)
- Use JavaScript
fetch
to get the JSON data - Use Handlebars to process the data
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Departments</title>
<link rel="stylesheet" href="styles/site.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.7/handlebars.min.js"
integrity="sha512-RNLkV3d+aLtfcpEyFG8jRbnWHxUqVZozacROI4J2F1sTaDqo1dPQYs01OMi1t1w9Y2FdbSCDSQ2ZVdAC8bzgAg=="
crossorigin="anonymous"></script>
<script>
let dataUrl = './json-courses.php';
let urlParams = new URLSearchParams(window.location.search);
console.log(urlParams.get('department_code'));
let department_code = urlParams.get('department_code');
document.addEventListener('DOMContentLoaded', function () {
fetch(dataUrl + '?department_code=' + department_code)
.then(response => response.json())
.then(data => {
console.log(data);
let mysource = document.getElementById('courses-list-template').innerHTML;
let mytemplate = Handlebars.compile(mysource);
let myresult = mytemplate(data)
document.getElementById('courses-list').innerHTML = myresult;
});
});
</script>
</head>
<body>
<h1>Harvard Extension School</h1>
<p><a href="departments.html">Return to Department List</a></p>
<div id="courses-list">
</div>
<div id="courses-list-template" class="handlebars">
<h2>{{ department_name }}</h2>
<p>{{ courses.length }} courses</p>
<div>
{{#courses}}
<section class="course">
<h2 class="abbrev">{{ short_title }}</h2>
<div>
<p class="term">{{ term }} {{ academic_year_display }}</p>
<p class="title">{{ title }}</p>
<p class="faculty">{{ faculty_description }}</p>
<p class="description">{{{ description }}}</p>
</div>
</section>
{{/courses}}
</div>
<footer>
<p><a href="./">PHP/mysql example list</a></p>
<p>This is a learning example to demonstrate PHP and mysql for the courses CSCI E-12 and CSCI S-12 taught by David
Heitmeyer. <br />
The real <a href="https://courses.dce.harvard.edu/">Harvard Extension School course search</a> is at: <a
href="https://courses.dce.harvard.edu/">courses.dce.harvard.edu</a>
</p>
</footer>
</body>
</html>
JavaScript Frameworks - Vue, React, Angular, Ember
Understanding client-side JavaScript frameworks | MDN
JavaScript frameworks are an essential part of modern front-end web development, providing developers with tried and tested tools for building scalable, interactive web applications.
CSCI E-12 Resources
Vue directives are built into markup (e.g. v-for
and v-bind
). The advantage here is that Vue takes care of updating content when underlying data changes.
Snippet of Vue code that formats list of resources:
<ul class="resources">
<li v-for="r in urls" class="resource">
<a v-bind:href="r.url">
<img v-if="r.image" v-bind:src="r.image" />
</a>
<div class="title">
<a v-bind:href="r.url">{{ r.title }}</a>
</div>
<div class="hostname">{{ r.hostname }}</div>
<div class="description">{{ r.description }}</div>
</li>
</ul>
And the JSON data (snippet) that powers it:
{
"urls": [
{
"url": "https://alistapart.com/",
"title": "A List Apart",
"description": "For people who make websites",
"image": "https://i2.wp.com/alistapart.com/wp-content/uploads/2019/03/cropped-icon_navigation-laurel-512.jpg?fit=512%2C512&ssl=1"
},
{
"url": "https://learn.jquery.com/",
"title": "jQuery Learning Center",
"keywords": "javascript, library",
"image": "https://cscie12.dce.harvard.edu/images/site-card-jquery.png"
},
{
"url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview",
"title": "An overview of HTTP | MDN",
"description": "HTTP is a protocol for fetching resources such as HTML documents. It is the foundation of any data exchange on the Web and it is a client-server protocol, which means requests are initiated by the recipient, usually the Web browser. A complete document is reconstructed the different sub-documents fetched, for instance, text, layout description, images, videos, scripts, and more.",
"image": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview/fetching_a_page.png"
},
{
"url": "http://www.w3.org/",
"title": "World Wide Web Consortium (W3C)",
"description": "The World Wide Web Consortium (W3C) is an international community where Member organizations, a full-time staff, and the public work together to develop Web standards.",
"image": "https://www.w3.org/Icons/WWW/w3c_home_nb-v.svg"
}, ... ]}
Sending Email
Mail service -- e.g. Mailgun, Sendgrid, etc.
submit.php Example (uses Mailgun)
<?php require_once 'vendor/autoload.php';
$loader = new \Twig\Loader\FilesystemLoader('./templates');
$twig = new \Twig\Environment($loader, [
'cache' => './compilation_cache',
'debug' => true,
'auto_reload' => true
]);
$requestTime = new DateTime();
$requestTime->setTimestamp($_SERVER['REQUEST_TIME']);
$requestTimeHuman = $requestTime->format('Y-m-d\TH:i:s');
$echocontent = $twig->render('form-response-template.html',
[
'getparams' => $_GET,
'postparams' => $_POST,
'httpheaders' => getallheaders(),
'httpmethod' => $_SERVER['REQUEST_METHOD'],
'serverinfo' => $_SERVER,
'requesttime' => $requestTimeHuman,
'httpreferer' => $_SERVER['HTTP_REFERER']
]);
?>
<?php
require 'vendor/autoload.php';
use Mailgun\Mailgun;
$mailto = filter_var($_POST['__mailto'], FILTER_VALIDATE_EMAIL);
$mailkey = '';
if (preg_match('/^csci(e|s)12\-(spring|summer|fall)-\d{4}-[a-z]+[0-9]+$/',$_POST['__mailkey'])) {
$mailkey = $_POST['__mailkey'];
}
// only send if POST and if __mailto and if __mailkey exist
if (strcmp($_SERVER['REQUEST_METHOD'],'POST') == 0 && $mailto && $mailkey ) {
error_log("FormSubmit | MAILGUN | $mailkey | $mailto |");
// First, instantiate the SDK with your API credentials
$MG_API_KEY = getenv('MG_API_KEY');
$MG_DOMAIN = getenv('MG_DOMAIN');
$MG_ = getenv('MG_');
$mg = Mailgun::create($MG_API_KEY); // For US servers
$domain = $MG_DOMAIN;
// Now, compose and send your message.
// $mg->messages()->send($domain, $params);
$mg->messages()->send($domain, [
'' => $MG_,
'to' => $mailto,
'subject' => 'Form Submission',
'html' => $echocontent
]);
}
echo($echocontent);
?>
form_response_template.html
This is a PHP "Twig" template.
<DOCTYPE html>
<html lang="en">
<head><title>Form Submission</title>
<style>
body, * { font-family: helvetica, sans-serif; }
body { margin: 1rem 5%; }
h2 { margin-top: 1.5rem; }
table, td, th, tr { border-collapse: collapse; }
table td, table th { border-collapse: collapse; vertical-align: top; padding: 0.5rem; border: thin solid #101010; }
table thead tr { color: #ffffff; background-color: rgb(100,100,100); font-size: larger;}
table tbody tr:nth-child(even) { background-color: rgb(240,240,240); }
table tbody tr th { text-align: left; }
footer { margin-top: 4rem; padding: 0.5rem; background-color: rgb(240,240,240); border-top: thin solid black; }
footer p { margin-top: 0.5em; margin-bottom: 0.5em; }
</style>
</head>
<body>
<h1>Form Submission</h1>
{% if getparams %}
<h2>GET Parameters</h2>
<table>
<thead>
<tr><th>Name</th><th>Value</th></tr>
</thead>
<tbody>
{% for key, value in getparams %}
<tr>
<th>{{ key }}</th>
<td>
{% if value is iterable %}
{% for v in value %}
{{ v }}{% if not(loop.last) %},<br/>{% endif %}
{% endfor %}
{% else %}
{{ value }}
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% if postparams %}
<h2>POST Parameters</h2>
<table>
<thead>
<tr><th>Name</th><th>Value</th></tr>
</thead>
<tbody>
{% for key, value in postparams %}
<tr>
<th>{{ key }}</th>
<td>
{% if value is iterable %}
{% for v in value %}
{{ v }}{% if not(loop.last) %},<br/>{% endif %}
{% endfor %}
{% else %}
{{ value }}
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% if serverinfo %}
<h2>Request Information</h2>
<table>
<thead>
<tr><th>Name</th><th>Value</th></tr>
</thead>
<tbody>
<tr><th>Request Time</th><td>{{ requesttime }}</td></tr>
<tr><th>Remote Address</th><td>{{ serverinfo['REMOTE_ADDR'] }}</td></tr>
<tr><th>HTTP Referrer</th><td><a href="{{ httpreferer }}">{{ httpreferer }}</a></td></tr>
<tr><th>HTTP Method</th><td>{{ httpmethod }}</td></tr>
</tbody>
</table>
{% endif %}
<footer>
<p>This form submission tool is only for use by current students in <a href="https://cscie12.dce.harvard.edu/">CSCI E-12</a> and <a href="https://cscis12.dce.harvard.edu/">CSCI S-12</a> courses.</p><p>David Heitmeyer | <a href="https://extension.harvard.edu/">Harvard Extension School</a> | <a href="https://summer.harvard.edu/">Harvard Summer School</a></footer>
</body>
</html>
Approaches to eCommerce
Shopify
Shopify is a hosted ecommerce solution. It uses the “liquid” templating language (similar to Mustache or Handlebars, but more capable).
{% for image in product.images %}
<img src="{{ image | img_url: '300x300' }}">
{% endfor %}
Commerce.js
Commerce.js describes itself as “Build eCommerce applications in vanilla JavaScript with our JS SDK and APIs. Create custom product displays, shopping carts, and checkouts with Commerce.js.
WooCommerce
WooCommerce is a popular ecommerce plugin used in WordPress
Oh, The Places You'll Go!

- Back-end programming (Python, JS)
- Front-end programming (JS, CSS)
- Content and Design
- Computer Science
- CSCI E-3 Introduction to Web Programming with JavaScript (Laurence Bouthillier)
- CSCI E-7 Introduction to Programming with Python
- CSCI E-10A/B Introduction to Computer Science Using Java - I and II (Henry Leitner)
- CSCI E-14A Building Interactive Web Applications for Data Analysis
- CSCI E-15 Web Server Frameworks with Laravel/PHP
- CSCI E-31 Web Application Development using Node.js (Laurence Bouthillier)
- CSCI E-33A Web Progamming with Python and JavaScript
- CSCI E-114 Web Application Development with Jamstack (Barrett, Bouthillier, Heitmeyer, and Hilborn)
- Digital Media
- DGMD E-2 Web Programming for Beginners with PHP
- DGMD E-20 Modern and Mobile Front-End Design I
DGMD E-27 Modern and Mobile Front-End Design II - DGMD E-23 Planning Successful Websites and Applications
- DGMD E-25 Developing Websites with WordPress
- DGMD E-26 Web Programming with WordPress
- DGMD E-28 Developing Single-Page Web Applications
Thank You!
<h1 data-to="Fall 2022 Class" data-from="David"> Thank You! </h1>