paint-brush
PHP Classes Use Case for Database Management in a Document Builderby@bobnoxious
151 reads

PHP Classes Use Case for Database Management in a Document Builder

by Bob WrightApril 11th, 2023
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

We have an application web site that uploads user content to be rendered as a sequentially paginated, accessible, performant, responsive design. The documents or comic books that the app generates use content in the form of images that represent a comic page, some text that is used as a caption for each page, **alt** **attribute** text for each image, and each page may also have an alternate image and an alternate caption.
featured image - PHP Classes Use Case for Database Management in a Document Builder
Bob Wright HackerNoon profile picture

We have an application website that uploads user content to be rendered as a sequentially paginated, accessible, performant, responsive design, illustrated serial content document, a.k.a. “a comic book.”


The documents or comic books that the app generates use content in the form of images that represent a comic page, some text that is used as a caption for each page, alt attribute text for each image, and each page may also have an alternate image and an alternate caption.


These images can be animations that play automatically or when activated, as well as still images. A page may also play audio content. With a comic of any length that can represent a good bit of data, and of course, we want to make that data, i.e., our content, available to a comic book’s audience, it falls to us to determine how to best accomplish this.

Content Data Storage

Perhaps the greatest consideration for the builder app involves our storage mechanism for the document or comic book content. The lead in the image above is a sort of digital “contact sheet” that displays all of the image content we plan to upload for use in our comic.


You can see that there are thirteen-page images, a page background image, a card image, and finally, an OG image.


These images total about twenty megabytes in size, and we could store them in the database itself using a cute data container item called a “blob” along with some data about each, or we could store them as files and place pointers to those files in the database.


One of the baseline requirements for our builder is that the comics or documents that it generates must be portable. My interpretation of that requirement is that the final deliverable, i.e., the comic, must be playable or viewable with only a web browser.


That doesn’t include a SQL server or database use. Of course, if we are always and only hosting these comics on our own site, the “no SQL” requirement might be relaxed.


We want the comics that our app generates to be a performant and responsive design. To accomplish this, our builder uses the HTML <picture> element along with the source and <srcset> modifiers and attributes.


In this scheme, the website presents the browser with a list of potential candidates as the image to display, and the browser then selects which image to download. In our case, we provide a choice among three image formats at five different pixel dimensions for each panel.


A quick pencil shows that means there are fifteen images in differing sizes and formats for each page or panel in the comic.


We have contrived a “standard” set of image sizes or dimensions based on five set image widths using the Bootstrap breakpoints, and we know that each of these sizes will be available in three formats.


These are JPG, WEBP, and AVIF still images and GIF, WEBP, and AVIF animations.


The approach used to obtain these ends is a hybrid method wherein we use the MySQL database to construct or generate the comics’ HTML without that database or its functions becoming a part of those comics.


Here is an example of such an <picture> element as we use them in our generated comics.

This snippet of HTML code above serves to display this comic page image.

The mySQL comicimages database entry used to generate this HTML code is a single row shown here next below.

As you might imagine, there is a bit of code between your having an image file and uploading it to be used to create this database entry and subsequently using the database entry to generate the HTML <picture> element and then further to display the page we see.


Let’s take a top-down tour through the builder to examine the importance of PHP Classes to our task.

PHP Classes, a Definition

PHP uses the concept of functions to accomplish many of its tasks and a class extends these functions. As our friends at zend.com so eloquently phrased this synopsis:


PHP functions are the first form of reusability you will generally encounter in PHP. They allow you to encapsulate logic that you can then repeat over and over again. You can pass a function arguments that it can then act on or consume in order to perform its logic.


A PHP class, and more generally, object-oriented programming, provides additional approaches to reusability, and can be used for a variety of purposes:


  • They can describe entities that have known properties and behaviors.
  • They can be used as messages to functions and other objects.
  • They can be used to group related behaviors or state.
  • They provide a way to describe hierarchies and inheritance within an application.


A class is a blueprint, defining a mix of properties and behaviors, that acts as a template for what are called objects, or instances of the class.


Two other important points deserve some mention.


A class property is part of object state and is an element that can be re-used and referred to within the class, and, depending on how it is defined, by consumers of class instances.


We can provide behavior by defining methods on the class. A method is a function scoped to the class instance.


That means it can access the property values associated with the instance of the class; and the values we have assigned can be accessed within methods it defines.


Just like normal functions, methods can accept arguments, and will have an associated return value.


In summary, Class is a programmer-defined data type, which includes local methods and local variables.

The Builder PHP Database Classes

Most of the builder's internal generator code is written in PHP, and the builder nominally has three database tables it uses with each of these encapsulated in its own Class.


The first of these Class files is named ComicsUser.class.php, and since our focus here is on building comics as opposed to gathering user data and authenticating users, we will summarize this Class by saying that it serves to store and subsequently provide data about our authenticated users; for our purposes, it simply saves and validates our user’s ID info (an authenticated email address).


There are two other PHP database Classes employed by the builder that are of import to our discussion, and as mentioned, each of these Classes represents a database table for the comic.


Let’s begin by creating a database to contain our two tables. This is the PHP code for the

createComicDataBase.php program to do this.

<?php
/*
 * createComicDataBase.php
 * create a db
*/
	// Database configuration
    $dbHost     = 'localhost'; //Database_Host
    $dbUsername = 'user'; //Database_Username
    $dbPassword = 'password'; //Database_Password

	// Connect to the server
	$conn = new mysqli($dbHost, $dbUsername, $dbPassword);
	if($conn->connect_error){ // limit information displayed on error
		die("Failed to connect with server. "/* . $conn->connect_error*/);
	} else { echo "Connected to server<br>";}
	/* --------------------
	 Create the database
	*/
	$sql = "CREATE DATABASE comicdata";
	if ($conn->query($sql) === TRUE) {
		echo "Database created successfully<br>";
	} else {
		echo "Error creating database: <br>"; // leave off $conn->error;
	}
	$conn->close();
?>


Inside this mySQL database, we have two data tables that we can create with these two programs below. The first program is createComicSQLTables.php shown here next which is used to create the table which stores some top-level data about each comic.


<?php
error_reporting(E_ALL); //disable for production
ini_set('display_errors', TRUE);

// Start session
session_name("Storybook");
require_once("/home/bitnami/session2DB/Zebra.php");
//	session_start();
// Include Comic class
require_once("/var/www/includes/Comic.class.php");
    $comic = new Comic();

	// try to create new image data table
    $comicData = $gallery->createTable();
?>


Notice that we have invoked our Comic.class.php program with the createComicSQLTables.php above to create our new database table.


We have a similar program named createComicImagesSQLTables.php shown here next which creates a table for comic images by invoking the ComicImages.class.php Class.


<?php
error_reporting(E_ALL); //disable for production
ini_set('display_errors', TRUE);

// Start session
session_name("Storybook");
include("/var/www/session2DB/Zebra.php");
//	session_start();
// Include Comic class
require_once("/var/www/includes/ComicImages.class.php");
    $gallery = new ComicImages();

	// try to create new image data table
    $galleryData = $gallery->createTable();
?>


Here next, is the first of our PHP Class code examples, the Comic.class.php program.

<?php
error_reporting(E_ALL); // disable this for production code
ini_set('display_errors', TRUE);
/*
 * Comic Class
 * This class is used for comic database related (connect, read, insert, update, and delete) operations
*/
	/*	TABLE `comicdata`
	 `comic_id`
	 `oauth_id`
	 `comic_name`
	 `comic_title`
	 `comic_subtitle`
	 `comic_category`
	 `comic_author`
	 `comic_script`
	 `comic_pencils`
	 `comic_inks`
	 `comic_coloring`
	 `comic_lettering`
	 `comic_publisher`
	 `comic_audience`
	 `artistname`
	 `cardemail`
	 `created`
	 `lastview`
	 `views`
	*/

class Comic {
	// Database configuration
    private $dbHost     = 'localhost'; //MySQL_Database_Host
    private $dbUsername = 'user'; //MySQL_Database_Username
    private $dbPassword = 'password'; //MySQL_Database_Password
    private $dbName     = 'comicdata'; //MySQL_Database_Name
    private $comicTbl   = 'comicdata';

    function __construct(){
        if(!isset($this->db)){
            // Connect to the database
            $conn = new mysqli($this->dbHost, $this->dbUsername, $this->dbPassword, $this->dbName);
            if($conn->connect_error){ // limit information displayed on error
                die("Failed to connect with database. "/* . $conn->connect_error*/);
            }else{
                $this->db = $conn;
            }
        }
    }
    
	/* --------------------
	create the comic table
	*/
public function createTable(){
   // Check whether user comic data already exists in database
	$checkQuery = "SELECT * FROM ".$this->comicTbl;
		// echo $prevQuery."<br>";
	$checkResult = $this->db->query($checkQuery);
	if($checkResult != NULL){
	$drop = "DROP TABLE ".$this->comicTbl.";";
		if ($this->db->query($drop) === TRUE) {
				echo "Comic Table dropped successfully<br>";
				} else {
				echo "Error dropping Comic Table: <br>"; // leave off $conn->error;
	}}
	$sql =
	 "CREATE TABLE IF NOT EXISTS `comicdata` (
	 `comic_id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
	 `oauth_id` varchar(24) COLLATE utf8mb4_unicode_ci NOT NULL,
	 `comic_name` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL,
	 `comic_title` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL,
	 `comic_subtitle` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL,
	 `comic_category` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
	 `comic_author` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
	 `comic_script` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
	 `comic_pencils` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
	 `comic_inks` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
	 `comic_coloring` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
	 `comic_lettering` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
	 `comic_publisher` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
	 `comic_audience` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
	 `artistname` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
	 `cardemail` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL,
	 `created` datetime DEFAULT NULL,
	 `lastview` datetime DEFAULT NULL,
	 `views` int(11) DEFAULT NULL
	) COLLATE=utf8mb4_unicode_ci;
	";
	if ($this->db->query($sql) === TRUE) {
		echo "Comic Table created successfully<br>";
		} else {
		echo "Error creating Comic Table: <br>"; // leave off $conn->error;
	}
}
	
	// ----------------------------
	// insert comic data into table
public function insertComic($comicData){
	if(!empty($comicData)){
		// Check whether user comic data already exists in database
		$prevQuery = "SELECT * FROM `".$this->comicTbl."` WHERE oauth_id = '".$comicData['oauth_id']."' AND comic_name = '".$comicData['comic_name']."'";
		//$_SESSION['prevQuery'] = $prevQuery;
		$prevResult = $this->db->query($prevQuery);
		/* determine number of rows in result set */
		 //printf("Result set has %d rows.<br>", $prevResult->num_rows);
		if($prevResult->num_rows == 0){
			// Insert comic data
			$query = "INSERT INTO `".$this->comicTbl."` (oauth_id, comic_name, comic_title, comic_subtitle, comic_category, comic_author, comic_script, comic_pencils, comic_inks, comic_coloring, comic_lettering, comic_publisher, comic_audience, artistname, cardemail, created) VALUES ('".$comicData['oauth_id']."', '".$comicData['comic_name']."', '".$comicData['comic_title']."', '".$comicData['comic_subtitle']."', '".$comicData['comic_category']."', '".$comicData['comic_author']."', '".$comicData['comic_script']."', '".$comicData['comic_pencils']."', '".$comicData['comic_inks']."', '".$comicData['comic_coloring']."', '".$comicData['comic_lettering']."', '".$comicData['comic_publisher']."', '".$comicData['comic_audience']."', '".$comicData['artistname']."', '".$comicData['cardemail']."', now())";
			$insert = $this->db->query($query);
			/*	$_SESSION['insertQuery'] = $query;
			if ($insert === TRUE) {
				$_SESSION['resultMsg'] = "Record updated successfully";
				//$_SESSION['insertCount'] = $_SESSION['insertCount'] + 1;
			} else {
				$_SESSION['resultMsg'] = "Error updating record"; // leave off $conn->error;
			} */
		}
		// Get comic data from the database
		$result = $this->db->query($prevQuery);
		$comicData = $result->fetch_assoc();
	}
    // Return comic data
    return $comicData;
}

	// ---------------------------------
	// return an array of comic names
public function listComic($comic_name){
	if(!empty($comic_name)){
		// comic data exists in database
		$comicData = array();
		// execute function
			$Query = "SELECT * FROM `".$this->comicTbl."` WHERE comic_name LIKE '".$comic_name."'";
		$Result = $this->db->query($Query);
		/* determine number of rows in result set */
		 //printf("Result set has %d rows.<br>", $Result->num_rows);
		if($Result) { // comic name values into an array
			while($arr = $Result->fetch_assoc()) {
				$comicData[] = $arr['comic_name'];
			}
			$_SESSION['listcomicResult'] = $comicData;
		}
	// Return comic data
	return $comicData;
	}
}

	// ---------------------------------
	// return an array of comic names by oauth_id
public function listOauthcomic($oauth_id) {
	if(!empty($oauth_id)){
		// comic data exists in database
		$comicData = array();
		// execute function
		$Query = "SELECT * FROM `".$this->comicTbl."` WHERE oauth_id LIKE '".$oauth_id."'";
		$Result = $this->db->query($Query);
		/* determine number of rows in result set */
		 //printf("Result set has %d rows.<br>", $Result->num_rows);
		if($Result) { // comic name values into an array
			while($arr = $Result->fetch_assoc()) {
				$comicData[] = $arr['comic_name'];
			}
			$_SESSION['listcomicResult'] = $comicData;
		}
	// Return comic data
	return $comicData;
	}	
}

	// ---------------------------------
	// return an array of comic names and oauth_ids by datetime age
public function listAgedComic($interval = 8) {
	$comicData = array();
	// execute function
	$Query = "SELECT * FROM `".$this->comicTbl."` WHERE created < DATE_SUB(NOW(), INTERVAL '".$interval."' HOUR)";
	$Result = $this->db->query($Query);
	/* determine number of rows in result set */
	 //printf("Result set has %d rows.<br>", $Result->num_rows);
	if($Result) { // comic values into an array
		while($arr = $Result->fetch_assoc()) {
			$comicData[] = $arr['comic_name'] . ',' . $arr['oauth_id'];
		}
	// Return comic data
	return $comicData;
	}
}

// ---------------------------------
	// delete an array of comic records by comic name
public function deleteComic($comic_name){
	if(!empty($comic_name)){
		// comic data exists in database
		$comicData = array();
		// execute function
		$Query = "SELECT * FROM `".$this->comicTbl."` WHERE comic_name LIKE '".$comic_name."%'";
		$Result = $this->db->query($Query);
		/* determine number of rows in result set */
		 //printf("Result set has %d rows.<br>", $Result->num_rows);
		if($Result) { // comic values into an array
			while($arr = $Result->fetch_assoc()) {
				$comicData[] = $arr['comic_name'];
				$comic_name = $arr['comic_name'];
                $query = "DELETE FROM `".$this->comicTbl."` WHERE comic_name = '".$comic_name."'";
				//echo $query."<br>";
                $delete = $this->db->query($query);
			}
		// Return comic data
		return $comicData;
		}
	}
}

// ---------------------------------
	// delete an array of comic records by oauth id
public function deleteOauthComic($oauth_id){
	if(!empty($oauth_id)){
		// comic data exists in database
		$comicData = array();
		// execute function
		$Query = "SELECT * FROM `".$this->comicTbl."` WHERE oauth_id LIKE '".$oauth_id."'";
		$Result = $this->db->query($Query);
		/* determine number of rows in result set */
		 //printf("Result set has %d rows.<br>", $Result->num_rows);
		if($Result) { // comic_name values into an array
			while($arr = $Result->fetch_assoc()) {
				$comicData[] = $arr['oauth_id'];
				$oauth_id = $arr['oauth_id'];
                $query = "DELETE FROM `".$this->comicTbl."` WHERE oauth_id = '".$oauth_id."'";
				//echo $query."<br>";
                $delete = $this->db->query($query);
			}
		// Return comic data
		return $comicData;
		}
	}
}

	// ---------------------------------
	// return a comic record
public function returnComicRecord($comic_name){
	$comicData = '';
	if(!empty($comic_name)){
		// Check whether comic data exists in database
		//echo "comic_name : ".$userData['comic_name']."<br>";
		$Query = "SELECT * FROM `".$this->comicTbl."` WHERE comic_name = '".$comic_name."'";
		$Result = $this->db->query($Query);
		/* determine number of rows in result set */
		// printf("Result set has %d rows.<br>", $Result->num_rows);
		if($Result->num_rows == 1){
		// Get comic data from the database
		$result = $this->db->query($Query);
		$comicData = $result->fetch_assoc();
		}
	}
	// Return comic data
	return $comicData;
}

	// ------------------------------------
	// update views count and lastview date
public function updateComic($comic_name){
	if(!empty($comic_name)){
		// Check whether user comic data already exists in database
		$prevQuery = "SELECT * FROM `".$this->comicTbl."` WHERE comic_name = '".$comic_name."'";
		$prevResult = $this->db->query($prevQuery);
		/* determine number of rows in result set */
		// printf("Result set has %d rows.<br>", $prevResult->num_rows);
		if($prevResult->num_rows == 1){
			// Update comic data if already exists
			// change views = '".$comicData['views']."', lastview = '".$comicData['lastview']."',
			$query = "UPDATE `".$this->comicTbl."` SET views = views+1, lastview = NOW() WHERE comic_name = '".$comic_name."'";
			//echo $query."<br>";
			$update = $this->db->query($query);
		}
		// Get comic data from the database
		$result = $this->db->query($prevQuery);
		$comicData = $result->fetch_assoc();
	}
	// Return comic data
	return $comicData;
}

	// ------------------------------------
	// delete a comic record from the table
public function deleteComicRecord($comic_name){
	if(!empty($comic_name)){
		// Check whether user comic data already exists in database
		$prevQuery = "SELECT * FROM `".$this->comicTbl."` WHERE comic_name = '".$comic_name."'";
		$prevResult = $this->db->query($prevQuery);
		/* determine number of rows in result set */
		// printf("Result set has %d rows.<br>", $prevResult->num_rows);
		if($prevResult->num_rows == 1){
			// DELETE comic data if already exists
			// change views = '".$comicData['views']."', lastview = '".$comicData['lastview']."',
			$query = "DELETE FROM `".$this->comicTbl."` WHERE comic_name = '".$comic_name."'";
			//echo $query."<br>";
			$delete = $this->db->query($query);
		}
		// Get comic data from the database
		$result = $this->db->query($prevQuery);
		$comicData = $result->fetch_assoc();
	}
	// Return comic data
	return $comicData;
}
	// ------------------------------------
}
?>


This Class works in conjunction with the second builder PHP Class program, ComicImages.class.php shown here below.


<?php
error_reporting(E_ALL); // disable this for production code
ini_set('display_errors', TRUE);
/*
 * Comic Images Class
 * This class is used for comic images db table related (connect, read, insert, update, and delete) operations
*/
	/*	TABLE `comicimagedata`
	 `comic_id`
	 `comic_name`
	 `oauth_id`
	 `image_hash`
	 `filename`
	 `filetype`
	 `width`
	 `height`
	 `created`
	*/

class ComicImages {
	// Database configuration
    private $dbHost     = 'localhost'; //MySQL_Database_Host
    private $dbUsername = 'user'; //MySQL_Database_Username
    private $dbPassword = 'password'; //MySQL_Database_Password
    private $dbName     = 'comicdata'; //MySQL_Database_Name
    private $comicImageTbl   = 'comicimagedata';

    function __construct(){
        if(!isset($this->db)){
            // Connect to the database
            $conn = new mysqli($this->dbHost, $this->dbUsername, $this->dbPassword, $this->dbName);
            if($conn->connect_error){ // limit information displayed on error
                die("Failed to connect with database. "/* . $conn->connect_error*/);
            }else{
                $this->db = $conn;
            }
        }
    }
    
	/* --------------------
	create the comic table
	*/
public function createTable(){
   // Check whether user comic data already exists in database
	$checkQuery = "SELECT * FROM ".$this->comicImageTbl;
		// echo $prevQuery."<br>";
	$checkResult = $this->db->query($checkQuery);
	if($checkResult != NULL){
	$drop = "DROP TABLE ".$this->comicImageTbl.";";
		if ($this->db->query($drop) === TRUE) {
				echo "Comic Images Table dropped successfully<br>";
				} else {
				echo "Error dropping Comic Images Table: <br>"; // leave off $conn->error;
	}}
	$sql =
	 "CREATE TABLE IF NOT EXISTS `comicimagedata` (
	 `comic_id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
	 `comic_name` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL,
	 `oauth_id` varchar(24) COLLATE utf8mb4_unicode_ci NOT NULL,
	 `image_hash` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL,
	 `filename` varchar(256) COLLATE utf8mb4_unicode_ci NOT NULL,
	 `filetype` varchar(5) COLLATE utf8mb4_unicode_ci NOT NULL,
	 `width` int (5) NOT NULL,
	 `height` int (5) NOT NULL,
	 `created` datetime DEFAULT NULL
	) COLLATE=utf8mb4_unicode_ci;
	";
	if ($this->db->query($sql) === TRUE) {
		echo "Comic Images Table created successfully<br>";
		} else {
		echo "Error creating Comic Images Table: <br>"; // leave off $conn->error;
	}
}
	
	// ----------------------------
	// insert comic data into table
public function insertComicImages($comicData){
	if(!empty($comicData)){
		// Check whether user comic data already exists in database
		$prevQuery = "SELECT * FROM `".$this->comicImageTbl."` WHERE filename = '".$comicData['filename']."' AND comic_name = '".$comicData['comic_name']."'";
		//$_SESSION['prevQuery'] = $prevQuery;
		$prevResult = $this->db->query($prevQuery);
		/* determine number of rows in result set */
		 //printf("Result set has %d rows.<br>", $prevResult->num_rows);
		if($prevResult->num_rows == 0){
			// Insert comic data
			$query = "INSERT INTO `".$this->comicImageTbl."` (comic_name, oauth_id, image_hash, filename, filetype, width, height, created) VALUES ('".$comicData['comic_name']."', '".$comicData['oauth_id']."', '".$comicData['image_hash']."', '".$comicData['filename']."', '".$comicData['filetype']."', '".$comicData['width']."', '".$comicData['height']."', now())";
			$insert = $this->db->query($query);
			/*	$_SESSION['insertQuery'] = $query;
			if ($insert === TRUE) {
				$_SESSION['resultMsg'] = "Record updated successfully";
				//$_SESSION['insertCount'] = $_SESSION['insertCount'] + 1;
			} else {
				$_SESSION['resultMsg'] = "Error updating record"; // leave off $conn->error;
			} */
		}
		// Get comic data from the database
		$result = $this->db->query($prevQuery);
		$comicData = $result->fetch_assoc();
	}
    // Return comic data
    return $comicData;
}

	// ---------------------------------
	// return an array of comic image record keys by comic name
public function listComicImages($comic_name, $like = false){
	$comicData = '';
	if(!empty($comic_name)){
		// comic data exists in database
		$comicData = array();
		// execute function
		if($like === true) {
			$Query = "SELECT * FROM `".$this->comicImageTbl."` WHERE comic_name LIKE '".$comic_name."%'";
		} else {
			$Query = "SELECT * FROM `".$this->comicImageTbl."` WHERE comic_name LIKE '".$comic_name."'";
		}
		$Result = $this->db->query($Query);
		/* determine number of rows in result set */
		 //printf("Result set has %d rows.<br>", $Result->num_rows);
		if($Result) { // filename values into an array
			while($arr = $Result->fetch_assoc()) {
				$comicData[] = $arr['filename'];
			}
			//$_SESSION['listcomicResult'] = $comicData;
		}
	// Return comic data
	return $comicData;
	}
}

	// ---------------------------------
	// return an array of comic record keys by oauth_id
public function listOauthcomic($oauth_id) {
	if(!empty($oauth_id)){
		// comic data exists in database
		$comicData = array();
		// execute function
		$Query = "SELECT * FROM `".$this->comicImageTbl."` WHERE oauth_id LIKE '".$oauth_id."'";
		$Result = $this->db->query($Query);
		/* determine number of rows in result set */
		 //printf("Result set has %d rows.<br>", $Result->num_rows);
		if($Result) { // filename values into an array
			while($arr = $Result->fetch_assoc()) {
				$comicData[] = $arr['filename'];
			}
			$_SESSION['listcomicResult'] = $comicData;
		}
	// Return comic data
	return $comicData;
	}	
}

	// ---------------------------------
	// return an array of comic record keys by datetime age
public function listAgedComicImages($interval = 8) {
	$comicData = array();
	// execute function
	$Query = "SELECT * FROM `".$this->comicImageTbl."` WHERE created < DATE_SUB(NOW(), INTERVAL '".$interval."' HOUR)";
	$Result = $this->db->query($Query);
	/* determine number of rows in result set */
	 //printf("Result set has %d rows.<br>", $Result->num_rows);
	if($Result) { // filename values into an array
		while($arr = $Result->fetch_assoc()) {
			$comicData[] = $arr['comic_name'] . ',' . $arr['filename'];
		}
	// Return comic data
	return $comicData;
	}
}

// ---------------------------------
	// delete an array of comic records by comic name
public function deleteComicImages($comic_name){
	if(!empty($comic_name)){
		// comic data exists in database
		$comicData = array();
		// execute function
		$Query = "SELECT * FROM `".$this->comicImageTbl."` WHERE comic_name LIKE '".$comic_name."%'";
		$Result = $this->db->query($Query);
		/* determine number of rows in result set */
		 //printf("Result set has %d rows.<br>", $Result->num_rows);
		if($Result) { // filename values into an array
			while($arr = $Result->fetch_assoc()) {
				$comicData[] = $arr['filename'];
				$filename = $arr['filename'];
                $query = "DELETE FROM `".$this->comicImageTbl."` WHERE filename = '".$filename."'";
				//echo $query."<br>";
                $delete = $this->db->query($query);
			}
		// Return comic data
		return $comicData;
		}
	}
}

// ---------------------------------
	// delete an array of comic records by oauth id
public function deleteOauthComic($oauth_id){
	if(!empty($oauth_id)){
		// comic data exists in database
		$comicData = array();
		// execute function
		$Query = "SELECT * FROM `".$this->comicImageTbl."` WHERE oauth_id LIKE '".$oauth_id."'";
		$Result = $this->db->query($Query);
		/* determine number of rows in result set */
		 //printf("Result set has %d rows.<br>", $Result->num_rows);
		if($Result) { // filename values into an array
			while($arr = $Result->fetch_assoc()) {
				$comicData[] = $arr['filename'];
				$filename = $arr['filename'];
                $query = "DELETE FROM `".$this->comicImageTbl."` WHERE filename = '".$filename."'";
				//echo $query."<br>";
                $delete = $this->db->query($query);
			}
		// Return comic data
		return $comicData;
		}
	}
}

	// ---------------------------------
	// return a comic record
public function returnComicRecord($filename){
	if(!empty($filename)){
		// Check whether comic data exists in database
		//echo "comic_name : ".$userData['comic_name']."<br>";
		$Query = "SELECT * FROM `".$this->comicImageTbl."` WHERE filename = '".$filename."'";
		$Result = $this->db->query($Query);
		/* determine number of rows in result set */
		// printf("Result set has %d rows.<br>", $Result->num_rows);
		if($Result->num_rows == 1){
		// Get comic data from the database
		$result = $this->db->query($Query);
		$comicData = $result->fetch_assoc();
	// Return comic data
	return $comicData;
		}
	}
}

	// ------------------------------------
	// delete a comic record from the table
public function deleteComicRecord($filename){
	if(!empty($filename)){
		// Check whether user comic data already exists in database
		$prevQuery = "SELECT * FROM `".$this->comicImageTbl."` WHERE filename = '".$filename."'";
		$prevResult = $this->db->query($prevQuery);
		/* determine number of rows in result set */
		// printf("Result set has %d rows.<br>", $prevResult->num_rows);
		if($prevResult->num_rows == 1){
			// DELETE comic data if already exists
			// change views = '".$comicData['views']."', lastview = '".$comicData['lastview']."',
			$query = "DELETE FROM `".$this->comicImageTbl."` WHERE filename = '".$filename."'";
			//echo $query."<br>";
			$delete = $this->db->query($query);
		}
		// Get comic data from the database
		$result = $this->db->query($prevQuery);
		$comicData = $result->fetch_assoc();
	// Return comic data
	return $comicData;
}	}

/* close connection */
//$mysqli->close();
}
?>


Before we continue our explanation, we might note that the Comic.class database that is created is intended to be permanent; this data will be saved for use in the Comics Gallery where the collected comics are displayed.


The ComicImages.class database is intended to be temporary and used to build the comic after which it is no longer needed and may be deleted.


Now, let’s look at how these Classes are used by the builder to create a comic.

PHP Database Class Usage In the Builder

Once a user has successfully logged into the comic book builder application, they are presented with this form by the index.php program.

If the user scrolls down the index.php page without entering any data, they will encounter a screen that shows empty fields for the comic data similar to the one below.


The PHP $_SESSION data at this time is reflected by this dumpSession screen shown here next.

If the user provides the requested data for a number of the fields in our form, we may get a $_SESSSION dump which reflects that data as shown in this next screen.

So far in our index program, all of the data we have supplied is only stored in the temporary storage provided by the $_SESSION array. Let’s assume that we are now on this index program screen shown here next.


The questions we see here, or the data requested, are the names of two image files, one being the comic pages background image, and the other being an image to be used on the Comics Gallery display card for this comic.


Clicking the Select an image button for the comic Background image results in this file selection screen shown here. This is a JavaScript form that uses an AJAX call to pass the filename value to our PHP imgUploader.php program.

After it has filtered and processed the uploaded image and saved a set of image files in the formats and at the dimensions needed for use as the comic background image <picture> element’s <srcset> for this image, the imgUploader code invokes our ComicImages.class to save a “pointer” image file’s information in our images database table.


This snippet is the imgUploader code specific to our ComicImages.class use.


	  //reset($objects);
	  $objects = scandir($uploadDir);
	  foreach ($objects as $object) {
		if ($object != "." && $object != "..") {
		  unlink($uploadDir."/".$object);}
	  }
	$_SESSION['report'] = $report;
	$_SESSION['ErrReport'] = $ErrReport;
	//$_SESSION['Comicname'] = $Comicname;

	if(empty($ErrReport)) { 
    // set up the Comic image data array
	$ComicData = array();
    $ComicData['comic_name']   = $comic_name;
    $ComicData['oauth_id'] = $_SESSION['oauth_id'];
    $ComicData['image_hash'] = $imageHash;
    // $ComicData['image_key']	 = $imageKey;
    $ComicData['filename']   = $vpb_file_name;
    $ComicData['filetype']   = $vpb_file_type;
    $ComicData['width']   	= $width;
    $ComicData['height']   = $height;
    // Store image data in the session
    $_SESSION['ComicData'] = $ComicData;
	//if(!(($_SESSION['pageimage']) == 'altimgs')) { //alt images don't go in database
    // Initialize Image Comic class
    $comic = new ComicImages();
	// Insert image data to the database
	$Data = $comic->insertComicImages($ComicData);
	//if(file_exists($uploadDir.$vpb_file_name)) {
	//unlink($uploadDir.$vpb_file_name);}
	//rmdircontent($uploadDir);
	}
	if(empty($ErrReport)) { 
		//Display the file id
		echo $vpb_file_id;
	} else {
		//Display general system error
		echo 'general_system_error';
	}

}; // got an upload
};
}; // end POST
return;


Let’s take a look at the dumpSession output from this process of uploading our background image.

We can perform much the same operation to select and upload an image file to be used as the card image in the Comics Gallery entry. This screen below shows the display from our AJAX file uploader upon the successful upload of our card image.

If we now continue with the index form completion, we may now see a screen like this one which shows the summary screen we saw before except that the comic book data we have gathered thus far is now displayed.

And just below this Configuration Data table, we have a sort of rough preview of what the Comic Gallery Card will look like.


These two images, the background image and the card image, are each represented by a single pointer file entry in our Comic Images database table. These two entries are shown here next.



In addition to this data, we have also saved a lot of top-level sorts of data, the author names for example, about the comic in our Comics database table, and that data for this comic looks like the next image below.

The bottom of the index page now looks like this next screen.

If we then click the Apply button, we will obtain this display which informs us that we have saved our configuration data in a file and folder specific to our comic. Also stored in that comic folder are the variations of our background image and card image files.


Let’s take a look at the section of our saveConfig.php file invoked by the index program that deals specifically with Comic.class database to save some of this data.

<?php
	/*	TABLE `comicdata`
	 `comic_id`
	 `oauth_id`
	 `comic_name`
	 `comic_title`
	 `comic_subtitle`
	 `comic_category`
	 `comic_author`
	 `comic_script`
	 `comic_pencils`
	 `comic_inks`
	 `comic_coloring`
	 `comic_lettering`
	 `comic_publisher`
	 `comic_audience`
	 `artistname`
	 `cardemail`
	 `created`
	 `lastview`
	 `views`
	*/
	//$Comicbook = array();
	$Comicbook = array();
    $Comicbook['oauth_id'] = $oauth_id;
    $Comicbook['comic_name']   = $Comicname;
    $Comicbook['comic_title'] = $cardTitle;
    $Comicbook['comic_subtitle'] = $cardSubtitle;
    $Comicbook['comic_category']	 = $category;
    $Comicbook['comic_author']   = $authorname;
    $Comicbook['comic_script']   = $scriptname;
    $Comicbook['comic_pencils']   	= $pencilsname;
    $Comicbook['comic_inks']   = $inksname;
    $Comicbook['comic_coloring'] = $colorsname;
    $Comicbook['comic_lettering']	 = $lettersname;
    $Comicbook['comic_publisher']   = $publisher;
    $Comicbook['comic_audience']   = $audience;
    $Comicbook['artistname']   	= $artistname;
    $Comicbook['cardemail']   = $cardemail;
    
    // Store comic data in the session
    $_SESSION['Comicbook'] = $Comicbook;
	// Insert comic data to the database
		if($checkbox == 1) { //db not already open?
		require("/var/www/includes/Comic.class.php");
		$comicbook = new Comic(); }
	$Data = $comicbook->insertComic($Comicbook);

// write the configuration values and comics gallery card files
if($Comicname === '') {
	$noComicname = 'No Configuration Data!!!<br>';
	$deletedOldConfig = '';
	$wroteNewConfig = '';
	$deletedOldCard = '';
	$wroteNewCard = '';
	$clearedDB = '';
	$clearedComic = '';
} else {
	// write the config values file
	$file = $comicsDir.$Comicname.'/'.$Comicname.'.php';
	$deletedOldConfig = '';
	if(file_exists($file)) {
		unlink($file);
		$deletedOldConfig = "Deleted previous Configuration File<br>";}
	$return = file_put_contents($file, $configContent);
	$wroteNewConfig = '';
	if($return !== false) {
		$wroteNewConfig = 'Wrote a new Config File ' . $Comicname . '<br>'; }
	// write the comics gallery card file
	$cfile = $comicsDir.$Comicname.'.card';
	$deletedOldCard = '';
	if(file_exists($cfile)) {
		unlink($cfile);
		$deletedOldCard = "Deleted previous gallery Card File<br>";}
	$return = file_put_contents($cfile, $cardContent);
	$wroteNewCard = '';
	if($return !== false) {
		$wroteNewCard = 'Wrote a new gallery Card File ' . $Comicname . '<br>'; }
}
}
}
header("Refresh: 0; URL=./index.php#CfgSave");
if($Comicname === '') {
	echo "invalid operation.<br/><br/>";}
if(!($Comicname === '')) {
	echo "$Comicname is a valid filename string.<br/><br/>";}
echo "checkbox was ' . $checkbox . '<br>";
if(!($noComicname === '')) {
	echo $noComicname; }
if(!($deletedOldConfig === '')) {
	echo $deletedOldConfig; }
if(!($clearedComic === '')) {
	echo $clearedComic; }
if($clearedCdb != '') {
	echo $clearedCdb; }
if($clearedIdb != '') {
	echo $clearedIdb; }
if(!($wroteNewConfig === '')) {
	echo $wroteNewConfig; }
if(!($deletedOldCard === '')) {
	echo $deletedOldCard; }
if(!($wroteNewCard === '')) {
	echo $wroteNewCard; }
?>


If we now reload our index program, we can generate a new clean $_SESSION array to allow us a better view of the dumpSession screens to follow.

If we click Next in the Footer at the bottom of the index, it will take us to the getComic.php program and the screen shown here next.

If we now go through the browser file selection and tell getComic to Upload the chosen files, we end up with a display screen like the one here below.

These next screens present the dumpSession display after the last image in the table above has been uploaded and processed.

The code section we presented previously above from the end of the imgUploader program that uses the ComicsImages.class to store the pilot images in the database table is used here again.


This next table shows the ComicImages.class Table for the comic page pilot images.

The next steps the builder will take include uploading a caption file for each comic page or image panel and finally selecting and uploading an OG image using some of the steps above.


At that point, the remaining tasks are to take the images and text content we have prepared and merge that data into the comic itself.


So far, we have used our ComicImages.class to save data about our pointer files; now we will use that Class to extract data from our images table that we will use in the comic.


The last program involved in actually generating the comic is named makeComic.php, and it contains this section of code to interact with the ComicImages Table.

<!-- ++++++++++++++++++++ -->
<!--  build comic pages -->
<!-- ++++++++++++++++++++ -->
// Include ComicImages class
	/*	TABLE `comicimagedata`
	 `comic_id`
	 `comic_name`
	 `oauth_id`
	 `image_hash`
	 `filename`
	 `filetype`
	 `width`
	 `height`
	 `created`
	*/
//$imageList = array();
require("/var/www/includes/ComicImages.class.php");
    $comic = new ComicImages();
$imageList = $comic->listComicImages($Comicname);
//sort($imageList);
$_SESSION['imagelist'] = $imageList;
/*
$constring = print_r($imageList);
echo '<script>console.info('.$constring.')</script>';
*/
for ($i = 0; $i <  count($imageList); $i++) {
    $imageData = $comic->returnComicRecord($imageList[$i]);
	if ($imageData<> ' ') {
	   //echo $imageIndex ." = ".  $imageKey ." <br> ";
	   // $imageIndex = $imageIndex + 1;
		//echo $val .".jpg<br> ";
		//$imageKey = $val;
 	// get image data from the database
    // Store image data in the session
    $_SESSION['imageData'] = $imageData;
	//echo '<p>'; echo var_dump($imageData); echo '</p>';
	$filename = $imageData['filename'];
	$xmlFile = pathinfo($filename);
	$filenameNoExt = $xmlFile['filename'];
	$filetype = $imageData['filetype'];
	$_SESSION['filenameNoExt'] = $filenameNoExt;
	$width = $imageData['width'];
	$height = $imageData['height'];
	$created = $imageData['created'];
	$FigDesc = 'This is '.$filenameNoExt.'.';
	//$FigCntr = '[ '.$imageIndex.' of '.count($imageList).' ]';
	$pg = $i + 1;
	$FigCntr = '[&nbsp;p&emsp;'.$pg.'&nbsp;]';
	// now have an array of values for this image as large jpg
	// we generate the filenames for our other sizes and formats

	// ----------------------------------
	// process the source image

The steps that the makeComic program then takes involve using this data and our preset parameters to generate a Source and <srcset> construct for each comic image by using our database pilot file name to generate the list of image files we actually store on the server and then present in the comic file HTML.


Once we have generated our comic, the ComicImages.class database table is no longer used and may be deleted. We save the Comic.class database for use in our website Comic Gallery.


Now, let’s take a look at the comic we just generated.


Jingo Jango is a Space Ranger in the military branch of The Alliance.


He appears here in a Recruitment Advertisement for his employer.


Jingo Jango, Space Ranger

I serve The Alliance in the military policy enforcement branch.

My name is Jingo Jango, Space Ranger.

I have seen service with the fleet in far-away systems.

I have seen the Phaser beams split the darkness.

I have seen the collisions of saucer craft with the loss of all hands in a single flash.

I have witnessed the flashing death of battle cruisers with thousands lost in the burst.

I witnessed the collisions of our Euripedes Star Cruisers with the enemy's ships.

Yet, whether in Space...

Or on some surface...

We stand ready to serve, defend, and protect.

We have the metal,

And the battle experience to do the job at hand.

We are the Space Rangers.

Conclusion

OK folks, that’s all for now. Truly hope you enjoyed it and that it benefits your own web building. God Bless each and all. As always Criticisms, Comments, and Suggestions are welcome.