Session 13 - Server-Side, Part 1

Harvard Extension School  
Fall 2023

Course Web Site: https://cscie12.dce.harvard.edu/

Topics

  1. Announcements
  2. "Back end" (Server-Side) Web Development
  3. Server Side Rendering of Content (SSR)
  4. PHP Example with Courses Database
  5. Separation of Concerns
  6. {{Mustache}} Templates
  7. Improving the Hello! Greeting
  8. Sending Email
  9. CSR (Client Side Rendering)
  10. Next Time

Session 13 - Server-Side, Part 1, slide1
Announcements, slide2
Final Project Notes and Observations, slide3
"Back end" (Server-Side) Web Development, slide4
CSR or SSR or SSG, slide5
Server Side Rendering of Content (SSR), slide6
A Personal Greeting, slide7
A Personal Greeting, slide8
PHP Example with Courses Database, slide9
Harvard Extension Course Data, slide10
Data Table in a Relational Database, slide11
PHP Script to Connect to Database and Get List of Departments, slide12
Turn this into HTML Output, slide13
The entire "departments-simple.php", slide14
Adding another view - Department Course Listings, slide15
courses.php, slide16
Separation of Concerns, slide17
{{Mustache}} Templates, slide18
Mustache Departments, slide19
Mustache Courses, slide20
Improving the Hello! Greeting, slide21
Hello! Greeting, Improved, slide22
Sending Email, slide23
CSR (Client Side Rendering), slide24
Getting JSON from HTTP request, slide25
Let's Try It Out!, slide26
Apples, slide27
Apples, slide28
JS and fetch, slide29
Courses — PHP and JSON data, slide30
Front-end courses, slide31
Next Time, slide32

Presentation contains 32 slides

Announcements

Final Project Notes and Observations

"Back end" (Server-Side) Web Development

LanguageFrameworks/Platforms
JavaScript "Back-end": Node, Express
"Front-end": React, Vue, Angular, Ember
PHPLaravel, Symfony, CodeIgniter, CakePHP

PHP-based CMS: WordPress, Drupal, Joomla

PythonDjango, Flask, Zope, Plone
GoGin, Echo, Beego, etc.

CSR or SSR or SSG

Server Side Rendering of Content (SSR)

Web Program Examples

Markup or content is embedded within a program; program embedded into markup

first.py - Python

first.py

#!/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

first.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

courses

courses

Harvard Extension Course Data

Course Data in a Spreadsheet

course data loaded in a spreadsheet

Data Table in a Relational Database

RDBMS = Relational Database Management System

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
// host,    user,    password,  database 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.

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
// host,    user,    password,  database 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!

{{Mustache}} Templates

{{mustache}} is another widely used template system for JavaScript (and other languages!).

mustache

Mustache Departments

Mustache Template

mustache-dept.php

PHP

<?php

  // use Dotenv to load database info from .env file
  // DB_HOST, DB_USER, DB_PW,     DB_NAME
  // host,    user,    password,  database 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);
  $rows = $result->fetch_all(MYSQLI_ASSOC);
  
  $template_data['departments'] = $rows;

// 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
$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

<?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> 

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><!-- inline styles removed for clarity --></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>

CSR (Client Side Rendering)

Front-end JavaScript + templates and Back-end JSON

Departments

Courses

Getting JSON from HTTP request

JavaScript functions are often asynchronous -- the script continues to run before a step has completed!

Javascript "fetch"

fetch(url).then(response => response.json()).then(data => processData(data));

Let's Try It Out!

Apples


You may find a "JSON Viewer" plugin or extension for your browser useful if you work with JSON
json

Apples

The JavaScript:

let applesUrl = "https://cscie12.dce.harvard.edu/apples-pyo.php";
  document.addEventListener('DOMContentLoaded',function(){
    fetch(applesUrl)
      .then(response => response.json())
      .then(data => buildApplesList(data));
  });

  function buildApplesList(data){
    let template = document.getElementById('apple-template').innerHTML ;
    console.log(template);
    let compiledTemplate = Handlebars.compile(template);
    let rendered = compiledTemplate(data);
    document.getElementById('applelist').innerHTML = rendered;
  }

The template:

<template id="apple-template">
  <h2>Picking Now</h2>
    <ul>
      {{#apples.picking_now}}
        <li>{{ . }}
      {{/apples.picking_now}}
    </ul>

    <h2>Picking Soon</h2>
    <ul>
      {{#apples.picking_soon}}
        <li>{{ . }}
      {{/apples.picking_soon}}
    </ul>
  </template>

JS and fetch

/* mlb api;  sportId = 1 is major league */
  let urlTeams = "https://statsapi.mlb.com/api/v1/teams?sportId=1";

  document.addEventListener("DOMContentLoaded", function () {
    fetch(urlTeams)
      .then(response => response.json())
      .then(data => buildList(data.teams));
  });

Courses — PHP and JSON data

Two problems to solve here:

<?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)

<!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>

Next Time