Category: Uncategorized

Tomcat Base Setup With PHP Support

Tomcat Base Setup With PHP Support

Tomcat is an awesome server when wanting to run local webapps or have a LAN server. But, getting it setup can be a little confusing at first go. This tutorial will show you the common things to look at as well as change to get a functional Tomcat server. In addition, at the end of this, you will be able to run PHP scripts from Tomcat too. So, first things first, we need to download a few programs to get started. They are Tomcat, PHP/Java Bridge, and PHP-CGI.

Downloads

*** Note: We need two JARs that comprise PHP/Java Bridge. Simply go to the most recent version of the application under “Binary package” and then go to the “exploded” folder. From there, right-click each JAR link and do “Open Link In New Tab”. Then go to each tab so the page will load and begin downloading the JAR.


Setup

OK, having everything we need, extract Tomcat to wherever you want to store it. I have a specific directory were I hold self-contained applications. Make sure to name the Tomcat folder to something more readable than its original name and we’re good to go. We next need to move the two JARs to their new home, edit the proper config files, and start Tomcat.

Move to the freshly extracted Tomcat folder and go to the “lib” folder. Copy or move the two JARs you downloaded for PHP/Java Bridge to this location. Then, go up one directory and go to “conf”. Edit the following files (“server.xml”, “tomcat-users.xml”, “web.xml”) with the below information.


server.xml

Find the “Connector” that has port 8080 and change it to the following:

<Connector port="1120" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443"
           address="0.0.0.0" />
*** Note: You can leave the port value as is or use your own.
*** Note2: The “address” value isn’t needed unless you want to make your server available for your LAN or the Internet. You can even set it to 127.0.0.1 which means localhost so that you can come back and change it later.


tomcat-users.xml

For the users file, add a new user outside of the commented out text but still within the “tomcat-users” tag. Mine looks like the following:

<user username="toor" password="root" roles="manager-gui, admin-gui"/>
*** Note: These roles should only be available to the admin or not included.


web.xml

For the web file we need to add the proper information for PHP to work on our Tomcat server. We are also adding a “welcome-file” entry for index.php. So, first, add the following right after the opening “web-app” part.

<!-- PHP FOR TOMCAT -->

<listener>
    <listener-class>php.java.servlet.ContextLoaderListener</listener-class>
</listener>
<servlet>
    <servlet-name>PhpJavaServlet</servlet-name>
    <servlet-class>php.java.servlet.PhpJavaServlet</servlet-class>
</servlet>
<servlet>
    <servlet-name>PhpCGIServlet</servlet-name>
    <servlet-class>php.java.servlet.fastcgi.FastCGIServlet</servlet-class>
    <init-param>
        <param-name>prefer_system_php_exec</param-name>
        <param-value>On</param-value>
    </init-param>
    <init-param>
        <param-name>php_include_java</param-name>
        <param-value>Off</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>PhpJavaServlet</servlet-name>
    <url-pattern>*.phpjavabridge</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>PhpCGIServlet</servlet-name><url-pattern>*.php</url-pattern>
</servlet-mapping>
Then, scroll all the way down to where “welcome-file-list” attributes are set and add the following:
<welcome-file>index.php</welcome-file>
We are now ready to launch Tomcat and do some initial cleanup and setup.


Tomcat Start & Initial Setup

Tomcat Start

To start Tomcat, simply go up one directory and go to the “bin” folder. From there, on Linux, make sure “catalina.sh” is set with proper execute permissions. You can do it through the file manager or the command line. For the command line it is as follows:

chmod +x catalina.sh
On Windows, everything is already set for you. OK, let’s actually start Tomcat. To do this, open your terminal and move to the “bin” folder. Then execute the following based on your system:
*** Linux
./catalina.sh start

*** Windows
.\catalina.sh start
To stop it:
*** Linux
./catalina.sh stop

*** Windows
.\catalina.sh stop


Tomcat Manager & Tomcat Webapps

Now that Tomcat is running, go to localhost:<your-port> in a new Tab. It will load the Tomcat “Welcome Page” which has links to admin tools, doc pages, and example apps. Click on “Manager App” and if prompted enter the user and password you setup just a moment ago. From there, remove the examples app by clicking its “Undeploy” button if you don’t want it taking space. Keep the page open but open your file manager and go to Tomcat’s “webapps” directory. Once there, re-name the “ROOT” folder to “welcome” (without the quotations). Then, create a new folder and name it “ROOT” (again, without the quotations). Copy the “WEB-INF” folder from the “welcome” app’s folder to “ROOT”. Then, edit the “web.xml” to more appropriate entries for “display-name” and “description”. At this point, everything is setup as it should be and you are ready to test whether PHP is working on Tomcat. Though, before we do that, let’s restart Tomcat by stopping it and starting it again.


Testing PHP

To test PHP on Tomcat go to the “ROOT” folder and from there create an “index.php” file. Enter the following:

<?php 

echo "Hello World!";

?>
Go to localhost:<your-port> OR if you have manager still open press on your keyboard Ctrl+F5. This will clear the page cache and refresh the page. You should see in the “Path” column one that is “/”. Press it and it’ll do the same as opening localhost:<your-port> by opening the “ROOT” app. You should see “Hello World!” load up.


Conclusion

And you’re done! You can now use Tomcat to create webapps with Java or PHP or even both! At this point, it might be useful to setup proper SSL so certain local applications have proper security. But, this will be for another time.

Star Wars: Battlefront 2 (Classic) – Wine Patch

Star Wars: Battlefront 2 (Classic) – Wine Patch

Star Wars: Battlefront 2 (Classic) on Linux PC is great but can be better. Here is a useful Wine patch to play the game properly.

HTML App Launcher

HTML App Launcher

App Launcher
App Launcher

    
I love web technology for one simple reason; making GUIs that are useful and have great logic flow is easy to do and virtually universal for platform access. I’m a lazy guy and want to launch apps quickly and through my browser than having to go to a Start Menu or search for the proper cli command. Today, I’ll show you how to make it so you can launch your favorite apps through a web page. First, we need to get all the necessary programs and setup our project folder structure.


To Top


To Bottom

Programs & Project Structure

Installs

 sudo apt-get install sqlite3 php-sqlite3 sqlitebrowser php firefox 

The first few programs (sqlite3, php-sqlite3, and sqlitebrowser) are pretty straightforward for why we need them. These deal with our database and sqlitebrowser is a quick way of viewing, editing, and adding data entries to our database. PHP will be the server side language which we are using to interact with the database and run the programs we have. Firefox is the browser I’m using to view the app launcher and has a plugin you can install to set your default New Tab page. Now that we have these installed, let’s create our project folder and the skeletal structure.

Folder & File Setup

mkdir appRunner

cd appRunner

mkdir -p resources/{css,js,php,db}

touch index.html resources/css/base.css resources/css/main.css \
                 resources/js/events.js resources/js/launcher.js \
				 resources/php/launcher.php resources/php/dbController.php

    
Since I’m using Linux, I like running easy commands that’ll get the layout built quickly. We are simply making a folder called appRunner and then changing directory to it. We then make a parent folder called resources with the respective sub folders: css, js, php, and db. Once that is completed, we create a new index file plus a slew of files for the application itself. With the base layout created, we still have some preliminary work to do before writing code. Let’s get the database up and running with some app entries.

Database Setup & Enteries

cd resources/db/

sqlite3 apps.db

CREATE TABLE Apps(id INTEGER, app MAX, icon BLOB, command MAX);

    
INTEGER is just that, a number. MAX means that the field can take the largest string possible and BLOB means the field is able to store binary data such as the image itself. Now, let’s insert initial app data so we have reference info to work off of. Here I have added 4 entries using sqlitebrowser‘s interface. Note: You can add your own apps and their commands than use mine since you may or may not have what I have.

App data
App data

OK, we have the base application setup and we are ready to code. But, first, we are gunna review what our logic will be and why we setup everything the way we did.

Logic & Code Flow

HTML

<body onload="getApps()">

<div class="container">
    <div id="appsMenu">

    </div>

    <div id="message">

    </div>
</div>

<script src="resources/js/events.js" charset="utf-8"></script>
<script src="resources/js/launcher.js" charset="utf-8"></script>

     For this quick setup, the main focus is about the application list and a message field. We also want an onload event on the body to make a request to the server to return all stored apps in the database. In addition, we are splitting up the JavaScript scripts into two files to keep things cleaner. The events.js will handle user interactions while launcher.js is the meat of the client side logic. Code and the logic breakdown for these js files are further down.

CSS

.container {
    display: table;
    margin: 0 auto;
}

.app {
    float: left;
    padding: 0em 2em;
}

.app:hover {
    cursor: pointer;
    background-color: rgba(43, 126, 144, 1);
    color: rgba(255, 255, 255, 1);
}

.icon {
    width: 72px;
    height: 72px;
}

     Here is the most important part of our CSS files. We have two files but main.css has the core logic while base.css has some house cleaning logic. Here, we setup a container with a display of table and margins set to center align the div. Our .app sets our div elements to float left so that apps are listed in a row than column. We do padding to make things look nice and a hover part to indicate what’s being selected. The .icon CSS sets our app icon images to be 72×72 pixles.

JS

// What we are working from with our JavaScript logic
<div name="34::Leafpad" class="app">
<img class="icon" src="" />
<p class="appName">Leafpad</p>
</div>

document.ondblclick = (event) => {
    let elm = event.target;

    // left-click detect
    if (event.which == 1) {
        if (elm.className.includes("app")) {
            launchApp(elm.getAttribute("name"));
        } else if (elm.className.includes("icon") ||
                   elm.className.includes("appName")) {
                       launchApp(elm.parentElement.getAttribute("name"));
        }
    }
}

     Here is the double click logic when clicking on our listed application. Basically, we check to see if there are any class names and from there if we are clicking on the root or sub element of our HTML structure for our listed application. We could make this cleaner by having an internal div that’s absolute positioned and is z-indexed above the image and paragraph tag. Then, we would look for just that; but, this method is a little more robust if you want controls for the app such as deletion, hiding, renaming, or something else. We then call a command in our launcher.js file to run the application by sending info to the server. The info we send is the id and name which we get by pulling the name attribute info from the app’s root div.

const launchApp = (app) => {
    let args = app.split("::");
    doAjax("launchApp=true&id=" + args[0] + "&app=" + args[1]);
}

const doAjax = (data) => {
    let xhttp = new XMLHttpRequest();

    xhttp.onreadystatechange = function() {
        if (this.readyState === 4 && this.status === 200) {
            // Send the returned data to further process
            if (this.responseXML != null) {
                handleXMLReturnData(this.responseXML);
            } else {
                alertMessage("error", "No content returned. No apps in database.");
            }
        }
    };

    xhttp.open("POST", "resources/php/appManager.php", true);
    xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xhttp.overrideMimeType('application/xml'); // Force return to be XML
    xhttp.send(data);
}

     You will note that here we are splitting the passed string from the events.js into its respective id and app name to pass to our doAjax command. I’ve setup the data this way to try and insure there will be no duplicates in the database query return info. So, even if there is a duplicate id value the app name makes sure we get the correct one. The rest here is simple AJAX logic where we pass the arguments and an identifying argument to the server script to determine the proper action to take. We then process the XML return data from the server as a message or the application data we queried for.

const handleXMLReturnData = (xml) => {
    let rootTag = xml.children[0];
    if (rootTag.tagName.includes("LIST")) {
        //<APP>
        //  <ID><ID></ID>
        //  <NAME><APP_NAME></NAME>
        //  <ICON><BASE64_ENCODED_ICON></ICON>
        //</APP>

        let apps = rootTag.getElementsByTagName("APP");
        let size = apps.length;
        for (var i = 0; i < size; i++) {
            let app  = apps[i];
            let id   = app.children[0].innerHTML;
            let name = app.children[1].innerHTML;
            let icon = app.children[2].innerHTML;
            createAppRef(id, name, icon);
        }
    } else if (rootTag.tagName.includes("SERV_MSG")) {
        alertMessage(rootTag.className, rootTag.innerHTML);
    }
}

const createAppRef = (id, appName, icon) => {
    let divTag  = document.createElement("DIV");
    let imgTag  = document.createElement("img");
    let pTag    = document.createElement("P");
    let text    = document.createTextNode(appName);

    divTag.setAttribute("name", id + "::" + appName);
    divTag.className = "app";
    imgTag.className = "icon";
    pTag.className   = "appName";
    imgTag.src       = "data:image/png;base64," + icon;

    pTag.append(text);
    divTag.append(imgTag);
    divTag.append(pTag);
    document.getElementById('appsMenu').append(divTag);
}

Now, handleXMLReturnData is parsing the return data and either displaying a server message or returning the list of apps in the database. The listed apps are parsed from a loop and we create the proper HTML for each using createAppRef. Note that we simply create a div, img, and p tag and then setup proper class names and the root’s name attribute. For the image, b/c it’s stored as a BLOB we return a BASE64 encoded string which we assign to the src attribute of img. We are identifying them as png type images since that’s what I’m using for each. This keeps things quick ‘n dirty but isn’t the best setup long term. OK, let’s finish this up by looking at our main PHP file.

PHP

function launchApp($ID, $APP) {
    $db = new SQLite3('apps.db');

    if($db === false) {
        $message = "Server: [Error] --> Database connection failed!";
        serverMessage("error", $message);
        die("ERROR: Could not connect to db.");
    }

    $stmt = $db->prepare('Select command FROM Apps WHERE id = :id AND app = :app');
    $stmt->bindValue(":id", $ID, SQLITE3_INTEGER);
    $stmt->bindValue(":app", $APP, SQLITE3_TEXT);
    $res = $stmt->execute();

    $row = $res->fetchArray(SQLITE3_ASSOC);
    $command = 'nohup ' . $row['command'] . ' > /dev/null &';
    shell_exec($command);

    $message = "Server: [Success] --> Launched " . $APP . "!";
    serverMessage("success", $message);
}


// Determin action
chdir("../db/");
if (isset($_POST['getData'])) {
    getData();
} elseif (isset($_POST['launchApp'],
                $_POST['id'],
                $_POST['app'])) {
    launchApp($_POST['id'], $_POST['app']);
} else {
    $message = "Server: [Error] --> Illegal Access Method!";
    serverMessage("error", $message);
}

?>

     When we launch an app, all that we are really doing is passing the id and app name to the PHP scriopt. The script queries the database and returns the command that is stored. Then, the script will run a shell_exec command with the returned string. This is what launchApp is doing here. It then return a server message of success or failure which our JavaScript handles and puts onto our page. Look at the Full PHP section to see how the apps list is returned and how messages are handled.

Conclusion

Discussion

     And that’s it for this tut. It is a simple way of making a personalized launcher for your favorite apps so that you don’t need to go to the Start Menu each time. You can use this by running a quick and dirty server through this guide:


Servers
Quick Test Server

If you are using Firefox and want it as your default tab when you open new tabs then please check out my plugin: Alt Tab Page

Full Code

Full HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>App Runner</title>
    <link rel="stylesheet" href="resources/css/base.css">
    <link rel="stylesheet" href="resources/css/main.css">
</head>
<body onload="getApps()">

<div class="container">
    <div id="appsMenu">

    </div>

    <div id="message">

    </div>
</div>

<script src="resources/js/events.js" charset="utf-8"></script>
<script src="resources/js/launcher.js" charset="utf-8"></script>
</body>
</html>

Full CSS

base.css
html, body {
    margin: 0em;
	padding: 0em;
}

ul, ol, li {
    list-style: none;
}
main.css
.container {
    display: table;
    margin: 0 auto;
}

.app {
    float: left;
    padding: 0em 2em;
}

.app:hover {
    cursor: pointer;
    background-color: rgba(43, 126, 144, 1);
    color: rgba(255, 255, 255, 1);
}

.icon {
    width: 72px;
    height: 72px;
}


/* Messages coloring */
.error, .warnning, .success {
    float: left;
    clear: both;
    width: 100%;
    text-align: center;
}


.error { color: rgb(255, 0, 0); }
.warnning { color: rgb(255, 168, 0); }
.success { color: rgb(136, 204, 39); }

Full JS

events.js
document.ondblclick = (event) => {
    let elm = event.target;

    // left-click detect
    if (event.which == 1) {
        if (elm.className.includes("app")) {
            launchApp(elm.getAttribute("name"));
        } else if (elm.className.includes("icon") ||
                   elm.className.includes("appName")) {
                       launchApp(elm.parentElement.getAttribute("name"));
        }
    }
}
launcher.js
const getApps = () => {
    doAjax("getData=true");
}

const launchApp = (app) => {
    let args = app.split("::");
    doAjax("launchApp=true&id=" + args[0] + "&app=" + args[1]);
}

const doAjax = (data) => {
    let xhttp = new XMLHttpRequest();

    xhttp.onreadystatechange = function() {
        if (this.readyState === 4 && this.status === 200) {
            // Send the returned data to further process
            if (this.responseXML != null) {
                handleXMLReturnData(this.responseXML);
            } else {
                alertMessage("error", "No content returned. No apps in database.");
            }
        }
    };

    xhttp.open("POST", "resources/php/appManager.php", true);
    xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xhttp.overrideMimeType('application/xml'); // Force return to be XML
    xhttp.send(data);
}

const handleXMLReturnData = (xml) => {
    let rootTag = xml.children[0];
    if (rootTag.tagName.includes("LIST")) {
        let apps = rootTag.getElementsByTagName("APP");
        let size = apps.length;
        for (var i = 0; i < size; i++) {
            let app  = apps[i];
            let id   = app.children[0].innerHTML;
            let name = app.children[1].innerHTML;
            let icon = app.children[2].innerHTML;
            createAppRef(id, name, icon);
        }
    } else if (rootTag.tagName.includes("SERV_MSG")) {
        alertMessage(rootTag.className, rootTag.innerHTML);
    }
}

const createAppRef = (id, appName, icon) => {
    let divTag  = document.createElement("DIV");
    let imgTag  = document.createElement("img");
    let pTag    = document.createElement("P");
    let text    = document.createTextNode(appName);

    divTag.setAttribute("name", id + "::" + appName);
    divTag.className = "app";
    imgTag.className = "icon";
    pTag.className   = "appName";
    imgTag.src       = "data:image/png;base64," + icon;

    pTag.append(text);
    divTag.append(imgTag);
    divTag.append(pTag);
    document.getElementById('appsMenu').append(divTag);
}

const alertMessage = (type, message) => {
    document.getElementById('message').innerHTML =
        "<p class=\"" + type +"\">" + message + "</p>";
}

Full PHP

appManager.php
<?php
include_once 'serverMessanger.php';

function getData() {
    $db = new SQLite3('apps.db');

    if($db === false) {
        $message = "Server: [Error] --> Database connection failed!";
        serverMessage("error", $message);
        die("ERROR: Could not connect to db.");
    }

    $res = $db->query('Select id, app, icon FROM Apps');
    $GeneratedXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><LIST>";
    while ($row = $res->fetchArray(SQLITE3_ASSOC)) {
        $GeneratedXML .= "<APP>" .
               "<ID>"   . $row['id'] . "</ID>" .
               "<NAME>" . $row['app'] . "</NAME>" .
               "<ICON>" . base64_encode($row['icon']) . "</ICON>" .
           "</APP>";
    }
    $GeneratedXML .= "</LIST>";
    echo $GeneratedXML;
}

function launchApp($ID, $APP) {
    $db = new SQLite3('apps.db');

    if($db === false) {
        $message = "Server: [Error] --> Database connection failed!";
        serverMessage("error", $message);
        die("ERROR: Could not connect to db.");
    }

    $stmt = $db->prepare('Select command FROM Apps WHERE id = :id AND app = :app');
    $stmt->bindValue(":id", $ID, SQLITE3_INTEGER);
    $stmt->bindValue(":app", $APP, SQLITE3_TEXT);
    $res = $stmt->execute();

    $row = $res->fetchArray(SQLITE3_ASSOC);
    $command = 'nohup ' . $row['command'] . ' > /dev/null &';
    shell_exec($command);

    $message = "Server: [Success] --> Launched " . $APP . "!";
    serverMessage("success", $message);
}


// Determin action
chdir("../db/");
if (isset($_POST['getData'])) {
    getData();
} elseif (isset($_POST['launchApp'],
                $_POST['id'],
                $_POST['app'])) {
    launchApp($_POST['id'], $_POST['app']);
} else {
    $message = "Server: [Error] --> Illegal Access Method!";
    serverMessage("error", $message);
}

?>
serverMessanger.php
<?php
function serverMessage($TYPE, $MESSAGE) {
    $GeneratedXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
    $GeneratedXML .= "<SERV_MSG class='" . $TYPE . "'>" . $MESSAGE ."</SERV_MSG>";
    echo $GeneratedXML;
}
?>
HTML Fun & Random Tutorial

HTML Fun & Random Tutorial

I wash watching a show and it had a scene with a challenger board that had a honeycomb pattern in it with a gradient. I randomly thought to myself that I could do that with HTML and even animate it if I wished. So, for giggles, I decided to do just that and make a quick tutorial about it.

naruto_challenger_board
naruto_challenger_board

Thought Process

Let’s first cover my thought process. I immediately thought that I could do this with a PNG that had a honeycomb pattern. It’s cells would be black with the lines being transparent. From there, I could use CSS’s linear-gradient to get the two colors in the image. Doing some googling got me a tillable honeycomb image but I did have to use Gimp to get the transparent parts and color exchange from white to black. Here is the end result of that: Honeycomb Image From there all I had to do was get two divs and set one of the with the image as the background and the other as a linear-gradient. OK, so we are set with the logic. Let’s look at the CSS.

CSS

The CSS is pretty straightforward. We first make sure that the entire page is filled when we have our elements in it. So, we set padding and margins to zero for the html and body tags. We then define some base parameters for our two core div elements. I identafy them with IDs and they are overElm and underElm. We simply set their width and height settings to 100%. In addition, we set their positions fixed so that we can use z-index to place them in the proper top and bottom order.

Now, the overElm has its background set to url(“honeycomb.png”); and repeat is set for both x and y ordinates. Then, underElm has its z-index set to -100 to make certain it is below overElm. That covers the CSS section. We will do one other CSS related thing but it will be referenced in our JavaScript section. Let’s cover our body tabs we need.

html, body {
    margin: 0em 0em 0em 0em;
    padding: 0em 0em 0em 0em;
}

#overElm, #underElm {
     width: 100%;
     height: 100%;
     position: fixed;
}

#overElm {
     background-image: url("honeycomb.png");
     background-repeat: repeat;
}

#underElm {
    z-index: -100;
}

 

Tags

This part is super straightforward and so we an quickly go to the JavaScript section in a moment. Here is the breakdown. We have two div tags and they each have their respective IDs. See? Easypeasy. See below:

<div id="overElm"></div>
<div id="underElm"></div>

 

JavaScript

OK, this is the most meaty part of the logic. We are going to use the setInterval JavaScript function and to create the animation. In addition, we will check to see if we want an animation at all. Before we do this we want to create a number of variables for use.

First, we get the element reference for underElm. Then, we create two color variables to be used in our linear-gradient setting. In addition, we create two color percent variables in order to drive how much gradient there actually is. Here we will use 50% for both so that they equally consume space and that there actually isn’t any gradation.

We also will create a degree variable and interval rate variable. Interval rate will dictate if we want to have a static color split or animated one. From there, we setup an if check and see if our interval rate is less than 0. If it is, it sets a static linar-gradient. Or if greater than, it will animate via the setInterval function. We pass our arguments to it for usage. And we are done! You can chnge the clors, its opacity, speed, and more to get a cool look for an HTML page or even video if you manage it right. Full code and video is below.

var elm = document.getElementById("underElm");
var color1        = "#09c759";
var color2        = "#c82f46";
var color1Percent = "50%";
var color2Percent = "50%";
var degInt        = 45;
var intervalRate  = -1;  // - number means do static than intervaled degree change
                         // 20 is nice and fast  500 is gradual and lower

if (intervalRate < 0) {
    elm.style.background = "linear-gradient(" + degInt + "deg,"
                           + color1 + " " + color1Percent +","
                           + color2 + " " + color2Percent + ")";
} else {
    var interval = setInterval(function () {
        elm.style.background = "linear-gradient(" + degInt + "deg,"
                               + color1 + " " + color1Percent +","
                               + color2 + " " + color2Percent + ")";

        degInt = (degInt <= 405) ? degInt += 5 : degInt = 45;

    }, intervalRate, elm, color1, color1Percent,
                          color2, color2Percent);
}

 

Full HTML & Code

 

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Honeycomb Gradient</title>

        <style media="screen">
            html, body {
                margin: 0em 0em 0em 0em;
                padding: 0em 0em 0em 0em;
            }

            #overElm, #underElm {
                width: 100%;
                height: 100%;
                position: fixed;
            }

            #overElm {
                background-image: url("honeycomb.png");
                background-repeat: repeat;
            }

            #underElm {
                z-index: -100;
            }
        </style>
    </head>
    <body>
        <div id="overElm"></div>
        <div id="underElm"></div>

         <script type="text/javascript">
             var elm           = document.getElementById("underElm");
             var color1        = "#09c759";
             var color2        = "#c82f46";
             var color1Percent = "50%";
             var color2Percent = "50%";
             var degInt        = 45;
             var intervalRate  = -1; // - number means do static than intervaled degree change
                                     // 20 is nice and fast  500 is gradual and lower

             if (intervalRate < 0) {
                 elm.style.background = "linear-gradient(" + degInt + "deg,"
                                        + color1 + " " + color1Percent +","
                                        + color2 + " " + color2Percent + ")";
             } else {
                 var interval = setInterval(function () {
                     elm.style.background = "linear-gradient(" + degInt + "deg,"
                                            + color1 + " " + color1Percent +","
                                            + color2 + " " + color2Percent + ")";

                     degInt = (degInt <= 405) ? degInt += 5 : degInt = 45;

                 }, intervalRate, elm, color1, color1Percent,
                                       color2, color2Percent);
             }

         </script>
    </body>
</html>

 

Video

 

Email-to-SMS Gateway List With Setup & Code Example

Email-to-SMS Gateway List With Setup & Code Example

email_to_sms
email_to_sms

For personnel projects, one might need to send a message to a phone to give updates or alerts. This can be done relatively easily by using PHP and its “mail()” command. But, we need to know what gateway to send it to and what the number is. The number part is easy but gateways vary. So, here is a reference list of Email-to-SMS Gateways. In addition, there is a quick code reference part to help get the ball rolling. As a final point before starting, you will need a proper mailing system and FQDN to make sure messages get through. Some gateways are highly fickle and you might not always get the SMS sent through using this setup. So, don’t use this in a commercial context unless you do the aforementioned.

Code Reference:

First, you’ll need the program “mail()” uses to send messages. In a terminal do:

sudo apt-get install sendmail

Then, edit the host file found at /etc/hosts. You’ll have something like this at the top: 127.0.0.1 localhost. You need it to be setup the proper FQDN syntax; so, something like this: 127.0.0.1 localhost.example.com is needed. After all that is setup (You might need to reboot.) you simply need to insert into a PHP script the following:

$number   = "[email protected]";
$subject  = "Your sybject message here.";         // Not used in text messages per say
$tmessage = wordwrap("Your message here.", 70 );

mail($number, $subject, $tmessage);

Gateway List:

Cell Carrier Email Domain
AT&T Enterprise Paging page.att.net
AT&T Wireless txt.att.net
Alaska Communication Systems msg.acsalaska.com
Alltel  text.wireless.alltel.com
Now part of AT&T
Australia T-Mobile/Optus Zoo (Optus) optusmobile.com.au
Appears they charge for the service
Bell Mobility & Solo Mobile txt.bell.ca
Bluegrass Cellular sms.bluecell.com
Boost Mobile myboostmobile.com
Cellcom cellcom.quiktxt.com
Cellular South (C Spire) cellularsouth1.com
(now cspire1.com)
Centennial Wireless cwemail.com
Cincinnati Bell gocbw.com
Cingular cingular.com
Merged with AT&T Mobility 2007
Cingular Prepaid cingulartext.com
Cox Wireless Discontinued 2012
Cricket Wireless mms.cricketwireless.net
Digicel St. Lucia digitextlc.com
Fido fido.ca
Google Voice Not an actual carrier
GCI Alask Digitel (GCI) mobile.gci.net
IV Cellular (Illinois Valley Cellular) ivctext.com
i wireless (iWireless) iwspcs.net (T-Mobile)
iwirelesshometext.com (Sprint PCS)
Koodo Mobile msg.telus.com
Lime txt2lime.com
Metro PCS mymetropcs.com
Mobilicity No email-to-SMS service
MTS Mobility text.mtsmobility.com
NET10 Determine NET10’s carrier
Nex-Tech sms.nextechwireless.com
nTelos pcs.ntelos.com
Will change to Sprint early 2016
O2 (M-mail) mmail.co.uk
O2 Powered Networks  
O2 UK o2imail.co.uk
Optus optusmobile.com.au
Appears they charge for the service
Orange orange.net
PC Telecom mobiletxt.ca
PTel Mobile tmomail.net
Pioneer Cellular zsend.com
Pocket Wireless sms.pocket.com
Republic Wireless text.republicwireless.com
Rogers Wireless pcs.rogers.com
SaskTel sms.sasktel.com
Sprint messaging.sprintpcs.com
Straight Talk Determine Straight Talk’s carrier
Syringa Wireless rinasms.com
T-Mobile tmomail.net
T-Mobile UK t-mobile.uk.net
Telstra onlinesms.telstra.com
Telus Mobility msg.telus.com
Three three.co.uk
Tracfone Determine Tracfone’s carrier
US Cellular email.uscc.net
Unicel utext.com
Verizon vtext.com
Viaero viaerosms.com
Virgin Mobile vmobl.com
Virgin Mobile Canada vmobile.ca
Virgin Mobile UK vxtras.com
Vodafone No email-to-SMS service
Wind Mobile txt.windmobile.ca

Check out my article regarding test servers so you can test this out properly!

 

Servers
Quick Test Server

 

MPlayer Keyboard Controls and Shortcuts

MPlayer Keyboard Controls and Shortcuts

mplayer logo
mplayer logo

I love MPlayer but I don’t always recall its controls since its default GUI is bare bones and uses the keyboard to do most if not all of its actions. So, I’ve shamelessly referenced another site and am backing it up onto my site. Besides, one never knows how long a site might remain up and this info is too useful to have to recompile if lost.

To add to all of that, I’ve been thinking about doing a project where I edit the MPlayer source code to add a helpful popup that shows the control options in a pagnated way. I want this page to be a reference for it should I get the willpower to actually try and do this. Anyway, here are 74 MPlayer keyboard controls.

MPlayer Keyboard Shortcuts

Keyboard control
<- and -> Seek backward/forward 10 seconds.
up and down Seek forward/backward 1 minute.
pgup and pgdown Seek forward/backward 10 minutes.
[ and ] Decrease/increase current playback speed by 10%.
{ and } Halve/double current playback speed.
backspace Reset playback speed to normal.
< and > Go backward/forward in the playlist.
ENTER Go forward in the playlist, even over the end.
HOME and END next/previous playtree entry in the parent list
INS and DEL (ASX playlist only) next/previous alternative source.
p / SPACE Pause (pressing again unpauses).
. Step forward. Pressing once will pause movie, every consecutive press will play one frame and then go into pause mode again (any other key unpauses).
q / ESC Stop playing and quit.
+ and – Adjust audio delay by +/- 0.1 seconds.
/ and * Decrease/increase volume.
9 and 0 Decrease/increase volume.
( and ) Adjust audio balance in favor of left/right channel.
m Mute sound.
_ (MPEG-TS and libavformat only) Cycle through the available video tracks.
# (DVD, MPEG, Matroska, AVI and libavformat only) Cycle through the available audio tracks.
TAB (MPEG-TS only) Cycle through the available programs.
f Toggle fullscreen (also see -fs).
T Toggle stay-on-top (also see -ontop).
w and e Decrease/increase pan-and-scan range.
o Toggle OSD states: none / seek / seek + timer / seek + timer + total time.
d Toggle frame dropping states: none / skip display / skip decoding (see -framedrop and -hardframedrop).
v Toggle subtitle visibility.
j Cycle through the available subtitles.
y and g Step forward/backward in the subtitle list.
F Toggle displaying forced subtitles .
a Toggle subtitle alignment: top / middle / bottom.
x and z Adjust subtitle delay by +/- 0.1 seconds.
r and t Move subtitles up/down.
i (-edlout mode only) Set start or end of an EDL skip and write it out to the given file.
s (-vf screenshot only) Take a screenshot.
S (-vf screenshot only) Start/stop taking screenshots.
I Show filename on the OSD.
! and @ Seek to the beginning of the previous/next chapter.
D (-vo xvmc, -vf yadif, -vf kerndeint only) Activate/deactivate deinterlacer.
Hardware accelerated video output
1 and 2 Adjust contrast.
3 and 4 Adjust brightness.
5 and 6 Adjust hue.
7 and 8 Adjust saturation.
SDL Video Output Driver
c Cycle through available fullscreen modes.
n Restore original mode.
Multimedia Keyboard
PAUSE Pause.
STOP Stop playing and quit.
PREVIOUS and NEXT Seek backward/forward 1 minute.
GUI Support (if compiled in)
ENTER Start playing.
ESC Stop playing.
l Load file.
t Load subtitle.
c Open skin browser.
p Open playlist.
r Open preferences.
If TV or DVB support compiled
h and k Select previous/next channel.
n Change norm.
u Change channel list.
Navigate menus (if DVNAV support)
keypad 8 Select button up.
keypad 2 Select button down.
keypad 4 Select button left.
keypad 6 Select button right.
keypad 5 Return to main menu.
keypad 7 Return to nearest menu (the order of preference is: chapter->title->root).
keypad ENTER Confirm choice.
Teletext support (if compiled)
X Switch teletext on/off.
Q and W Go to next/prev teletext page.
mouse control
button 3 and button 4 Seek backward/forward 1 minute.
button 5 and button 6 Decrease/increase volume.
joystick control
left and right Seek backward/forward 10 seconds.
up and down Seek forward/backward 1 minute.
button 1 Pause.
button 2 Toggle OSD states: none / seek / seek + timer / seek + timer + total time.
button 3 and button 4 Decrease/increase volume.

If you’d like to check out another reference sheet, have a look at my HTML, CSS, and JavaScript Cheat Sheet that’s linked below!

Web Technologies
HTML, CSS, and JavaScript Cheat Sheet

 

 

Prevent SQL Injections

Prevent SQL Injections

sql injections
sql injections

Preventing SQL injections is pretty easy once you know what you are doing. Some of you who are new to databases might think about character substitutions, character escaping, or just outright banning of certain characters; but, those options are laborious and not nearly as simple or elegant. Instead, we can use a technique called SQL Parameterization. It’s a fancy word for a straightforward process. For this guide, I’ll be referencing a database titled Movies.

To explain it simply, what we are going to do is use a “?” in place of inserting our value. We then have our value tied to the “?” which will then be interpreted as a string literal. Since it is being handled as a string literal and is being kept from interpretation, this keeps us from having our databases deleted, stolen, or used in unforeseen ways.

The setup looks like this:

// Instead of this.
$updateComm = "SELECT title FROM Movies WHERE id = '" . $ID . "'";

// We have this.
$updateComm = "SELECT title FROM Movies WHERE id = ?";

Again, the question mark is like a reference marker/bind point. Our data gets tied to it and is never interpreted. We next do a prepare statement that’ll allow us to bind values. The first way we can do this is by binding the values to the field individually.

Let’s take a look:

// We first setup a command with the properly inserted question marks.
$updateComm = "UPDATE Movies SET title = ?, link = ?, date = ? WHERE id = ?";
 
// We then set it up for preparation.
$updateStatement = $db->prepare( $updateComm );

// We then insert to the bind points.
// Note: They are in order of appearance in the command. 
//       This is why we bind to title first and then links, etc.
//       Keep this in mind when setting up commands.
//       Also, we don't start at zero but one.
$updateStatement->bindValue( 1, "I, Robot", PDO::PARAM_STR );
$updateStatement->bindValue( 2, "LINK", PDO::PARAM_STR );
$updateStatement->bindValue( 3, "July 7, 2004", PDO::PARAM_STR );
$updateStatement->bindValue( 4, 666999, PDO::PARAM_INT );
 
// We then execute the command which is properly set up.
$updateStatement->execute();

The second option is to just pass the arguments as an array without individual binding. Note once more that it is all based on order of the question marks.

$updateComm = "UPDATE Movies SET title = ?, link = ?, date = ? WHERE id = ?";
 
// We then set it up for preparation.
$updateStatement = $db->prepare( $updateComm );

// Then, just pass parameters as an array to the execute method.
$updateStatement->execute( array( "I, Robot", "LINK", "July 7, 2004", 666999) );

In both cases, everything is properly sanitized for you and you don’t have to worry about rogue single quotes or DROP TABLE commands getting through. You’re done! Easy right? At this point, all you have to do is look up your language and how to do the above steps and implement them for secure database interactions. Look at Rosetta Code for how other languages setup parameterization. In addition, if you’ve read any of my other articles, pick a project like my PHP7, SQLite3, and Ajax Tutorial to practice this on in addition to learning other skills and techniques.

Simple PHP7, SQLite3, and AJAX Tutorial

Simple PHP7, SQLite3, and AJAX Tutorial

Ajax and PHP
Ajax and PHP

Using PHP and AJAX can be somewhat confusing. But, the benefits are countless when it comes to doing web related projects. So, I wanted to do a simple tutorial/example of how to get things setup and how to do some basic insert and retrieval of data. For this project, I’m using PHP7, SQLite3, AJAX, Firefox, and Atom. You can use any browser with debugging options and any integrated development environment (IDE) or text editor you want. I choose SQLite3 as my database because it’s lightweight and good for applications that need a database.


To Top


To Bottom

Setup

Creating The Layout & Files

Ultimately, my file and directory layout looks like this:

├── ajaxNphp  // This is my working dir
       ├── index.html
       ├── process.php
       └── resources
           └── server.db

The ajaxNphp folder is the root folder of this project. In this folder, we have a resources folder that holds the database and can hold CSS and JavaScript files among other stuff. ***Note: For this project, JavaScript and CSS are inline to the files! I’m trying to keep this as simple as possible.*** For this part, I recommend using the terminal since it can be faster and we will use it for some other stuff during this project. So, KEEP IT UP! Anyway, My project is located in my Downloads folder under the ajaxNphp folder.
So, I open a terminal and type:

cd ~/Downloads/ajaxNphp/

The tilda (~) means your home folder and the rest is pretty self explanatory. I then do:

mkdir resources && touch index.html process.php

This creates the resources directory where our database will go; if successful, it will then create our PHP and HTML files that we will use for the project. The next part is for us to actually install the tools so we can setup our database and start writing code.

The Tools

I’m using an Ubuntu based operating system so I’ll show the commands you need to get PHP7, SQLite3, and Firefox installed.

sudo apt-get install sqlite3 php-sqlite3 php firefox

OK, now let’s just check that we have the proper versions installed.

PHP Check

// This will somewhat cleanup the version info on retrieval
    php -v | awk '{ print $1 $2 }' | head -n1
    // I get PHP7.0.25-0ubuntu0.16.04.1 which is PHP 7.0.25, so I'm set.

SQLite Check

sqlite -version
    // I get 2.8.17
    
    // If you do too, try:
    sqlite3 -version
    // If you get a return, then you are set for SQLite3.
    // I get a return value so am set.

Ok, so now we need to determine an environment to work with. I recommend Atom because it has a robust set of plugins and themes that make it more pleasant to work with. You’ll need to get it through their website if you wish to use the same thing; but, any text editor will suit this project.

Setup The Database

OK, so we now need to setup a database that we can query and insert to by using AJAX, PHP7, and SQLite3. I hope you’ve kept your terminal open as we will now change directory (cd) into the resources directory and launch SQLite3. So, here is what we do:

cd resources/ && sqlite3 server.db

We will then be presented with:

SQLite version <Your SQLite3 Version>
    Enter ".help" for usage hints.
    sqlite>

If you are seeing this, then let’s go ahead and create our database. I setup three columns for this project and they are title, date, and link. Recall, I’m doing a movies database so the first is for movie titles. The second is for when it was released, and the third is the cover image. So let’s create the table in our database.
Simply do:

CREATE TABLE Movies(title MAX, date varchar(10), link MAX);

If it was successful, you should see NO ERRORS and if you run :

.tables

you’ll get it returned. MAX means that the field can take the largest string possible. The varchar(10) means the field is limited to ten characters. There are other data types such as ints, but we will ignore them for now. Now, let’s insert some initial movie data by doing these below commands one at a time. Make sure there is an ending semi-colon for each!

// Date is in MM/DD/YYYY format
    
    INSERT INTO Movies VALUES('Alien', '05/25/1979', 'https://images-na.ssl-images-amazon.com/images/I/61ujvw4OXNL._SX342_.jpg');
    
    INSERT INTO Movies VALUES('Contact', '07/11/1997', 'http://www.filmsgraded.com/posters/01/1/8/8/84a.jpg');
    
    INSERT INTO Movies VALUES('Paul', '03/18/2011', 'https://upload.wikimedia.org/wikipedia/en/thumb/9/96/Paul_poster.jpg/215px-Paul_poster.jpg');
    
    // Check your work
    SELECT * FROM Movies;
    // You should see the data you entered returned.
    
    // If so, then simply exit.
    .exit

Excellent! The commands are pretty simple to understand. They even give a hint of what is going on. We use “INSERT INTO” to start the insert process. We reference our “Movies” table we created and then pass “VALUES” which match up with our title, date, link table layout. We end each command with a semi-colon. Next, we need a server to process PHP commands, interpret our form data, retrieve our data, etc.

Setup The Server

There are many servers out there one can use and there are some servers that are for testing. If you want to see some options, read my post on Quick Test Servers. For this project, I’m using PHP’s built in server used for testing since it will process PHP and our HTML files.
If you’ve kept the terminal up do this:

cd .. && php -S 127.0.0.1:1212

It’s pretty straightforward for what we are doing here. We moved back to the top directory of the project using cd .. since we only moved down one directory, We then use the “php” command with “-S” as a switch to use its server. We give “-S” an argument of “localhost” (127.0.0.1) and a port of 1212. The port needs to be bigger than 1024 since any port lower and equal to that requires sudo to use. It then waits to process requests. We can use ctrl + c to kill the server which can be helpful for when we want to use ctrl + l to clear the terminal screen of any text output and restart. When your project is complete, you can omit the change directory command and just do the PHP et all part. Add an “&” to the command so that the process is persistent even if the terminal closes. Now, we are truly ready to code!

HTML

Our Basic HTML Template

Let’s start off with a basic HTML template that we will add to shortly:

<!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Test AJAX/PHP</title>
    
    <script type="text/javascript">
    </script>
    
    </head>
    <body>
    
    <h2>Save Movie Info</h2>
    <form action="process.php" method="post">
    <input type="text" title="Title" placeholder="Title" name="Title" value="">
    <input type="text" title="Date" placeholder="Date" name="Date" value="">
    <input type="text" title="Link" placeholder="Link" name="Link" value="">
    <input type="submit" name="saveInfo" value="Save">
    <button type="reset" value="Reset">Clear</button>
    </forn>
    
    
    <br/><br/>
    <h2>Search Movie Info</h2>
    <form>
    <input type="text" name="searchField"
    title="Search"
    placeholder="Search..."
    onkeyup="getData(this.value)"/>
    </form>
    <br/><br/>
    
    
    <div id="dynDataField"></div>
    </body>
    </html>

Let’s break this down. We have two forms with their own input fields. One form is used for saving new movie entries and the other searches the database and gets the data back. The form that saves new movie info has three fields and a submit button. The three fields correspond to the three columns in our database and Movies table. The submit action uses the forms submit action to send our process.php script POST data about the form for processing.

The search form has one input field and an onkeyup event that calls a function called “getData”. This function has a parameter passed to it of “this.value” which will take the query that one has typed in. AJAX will be used in this instance to get data from the server as we type in a character. We have a div tag with an ID of “dynDataField” that we will reference to insert the returned data from the server. This is our bare bones HTML. But, it is pretty useless. Clicking any of the buttons or typing a search does nothing. So, let’s create an AJAX script to get our already entered data!

AJAX

AJAX Search Script

At the heart of AJAX, there are 4 core steps for GET and 5 core steps for POST.

  1. Create an XMLHttpRequest object
  2. Setup an onreadystatechange function for the XMLHttpRequest object
  3. Open a connection with the XMLHttpRequest object
  4. With POST: Setup a setRequestHeader with an XMLHttpRequest object
  5. Send the data with an XMLHttpRequest object
    // Step 1: Create object
    var xhttp = new XMLHttpRequest();  // Create the xhttp object
    // Step 2: Setup an onreadystatechange function for the XMLHttpRequest object
    // This is actually run after send is done and the server spits out info.
    xhttp.onreadystatechange = function() {
        // Confirm we have a  successful connection. Then, receive the response info.
        // For PHP it is echo that sends it.
        // Loops seem to cause this to wait which means an array can be traversed
        // and the output could be written as a table, etc.
        if (this.readyState == 4 && this.status == 200) {
            // do something with the returned data
        }
    };
    // Step 3: Open connection
    // More or less, open a connection: @Params POST or GET, path to XML page or php script, set async t/f
    xhttp.open("GET", "process.php", true);
    // Step 4: Send the data and let server process it.
    //         After done processing it, onreadystatechange is triggered.
    xhttp.send();    // Start the process and send GET data
    
    
    //      For POST do and add these changes
    //  xhttp.open("POST", "process.php", true);
    // Used in POST to setup data types like JSON, XML, etc... MUST BE DONE AFTER OPEN
    // xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    // Example data structure for Sending POST with above RequestHeader. See that this mimics GET
    // xhttp.send("fname=Henry&lname=Ford");
    // xhttp.sebnd(formData);  // Can use a string variable with formatted data structure instead

The above is the process. Here is what we setup in our scripts tag that’s in the head tag:

function getData(query) {
    if (query == "") {
        document.getElementById("dynDataField").innerHTML = "<p></p>";
        return;
    } else {
        var xhttp = new XMLHttpRequest();  // Create the xhttp object
        var formData = "dbQuery=" + query; // Our query being setup for processing
        // This is actually run after open and send are done
        xhttp.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                updatePage(this);  // Send the returned data to further process
            }
        };
        xhttp.open("POST", "process.php", true);  // Open the connection
        xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xhttp.send(formData);    // Start the process
        
    }
}

function updatePage(returnData) {
    // Get the echoed data and insert to div of dynDataField
    document.getElementById("dynDataField").innerHTML = returnData.responseText;
}

OK, so we have two functions here. One is for getting the data and the other inserts the results into our div. Get data checks to see if the input field is empty and if so leaves things as they are. If there is data in the field, it is then inserted into a variable “formData” and tied in with “dbQuery=”. This is what PHP will look at and use to insert into a database query. We then setup a statechange listener to wait for the server to finish processing the search and we send the result to the other function.

After this setup part, we do the standard open process but use POST instead of GET. Then, we tell the server what kind of data this is. Recall, GET defines it for us but is limited and less secure while POST has more data formats and better security but we have to define it using the setrequestheader. We then send the data in its formatted string to the server for processing. This w3schools link has some more info about each part. In this instance, the PHP script transfers a string back to the requester. Note, we can transfer JSON, XML, and other data. But, a string or “responseText” is good for now.

Alright, all that’s left is to write our PHP script to process the search and our insert to table option.

PHP

Base PHP

We have three core parts for the PHP project. We want to determine which form sent the POST. We then call one of two functions. One function will search the database. The other function will insert to the database.
Here is the basic setup:

<?php
    
    // Retrieve data
    function searchDB($QUERY) {
    }
    
    // Save new entry
    function saveInfo($TITLE, $DATE, $INFOLINK) {
    }
    
    // Determin action
    if(isset($_POST['saveInfo'])) {
        saveInfo($_POST["Title"], $_POST["Date"], $_POST["Link"]);
    } elseif (isset($_POST['dbQuery'])) {
        searchDB($_POST['dbQuery']);
    } else {
        echo "<h2 style='width:100%;background-color:#ff0000;color:#ffffff;text-align:center;'>Error! Illegal Access Method!</h2>";
    }
    
    ?>

The part of interest here is the the determine action section. This is how we determine which function to call when a form is submitted or an AJAX call is made. If neither call the script, we drop an error and exit the script. We are simply checking if “saveInfo” or “dbQuery” are set. We then call the proper function and pass the data that is sent. Let’s now setup our search function.

Search Function

As you might have seen, we are calling our search function “searchDB” and we are passing the “dbQuery” value to it.
So let’s see how we connect to the database and return data:

try {
    $serverPDO = new SQLite3('resources/server.db');
    $query = "SELECT * FROM Movies WHERE title LIKE '%" . $QUERY . "%' OR " .
    "date LIKE '%" . $QUERY . "%' OR " .
    "link LIKE '%" . $QUERY . "%'";
    $result = $serverPDO->query($query);
    
    while ($row = $result->fetchArray()) {
        echo "<div style='float: left;margin-left: 1em; margin-right: 1em;'>" .
        "<a href=" . $row["link"] ." target='blank'>" .
        "<img style='width:8em; height:10em;' src='" . $row["link"] . "'/></a><br/>" .
        "Title: " . $row["title"] .
        "<br/>Date: " . $row["date"] . "</div>";
    }
    
    if ($result->fetchArray() == 0) {
        echo "<div style='float:left;width:100%; background-color:pink;color:#ffffff;text-align:center;'>Nothing Found...</div>";
    } else {
        echo "<div style='float:left;margin-top:2em;width:100%; background-color:lightgreen;color:#ffffff;text-align:center;'>Search Completed...</div>";
    }
} catch (Exception $e) {
    echo "<h2 style='width:100%; background-color:ff0000;color:#ffffff;text-align:center;'>Error!</h2><br/>" . $e;
}

Let’s break this down. In our “searchDB” function, we have a try catch block that checks any exception that might occur. Technically, we really should be more specific to what exceptions might occur but for now, this will suffice. We try to create an SQLite3 database object and give it a local path name of “resources/server.db”. This is set to the “serverPDO” variable. We then create a “query” variable of type string that comprises of an SQL command that very broadly makes the database look at he table and see if any field matches the query. Please note, this is a very in-efficient way to do this as it looks at each field and then sees if any part is like the query both in upper, lower, and mixed casing. If we were being efficient, we’d base our queries on the columns and have either multiple input fields for the search with a “submit” button or use other techniques to keep the searches quick. Since this is a small database, performance isn’t poor and we can get away with this in a general context. Take note that the VALUES section is ordered just like we ordered it when we created the table columns.

Anyway, we then execute the query and get the result set into the “result” variable. This is essentially a 2D array that comprises an array of result objects that then have an array of values for each object. This is why we use the while loop and access the “row” and then any values there in. We assign the values to a string formatted with HTML markup that is then echoed. After that, we echo whether we traversed an arrays by saying the search was or was not found.

As I understand it, the “onreadystatechange” is triggered after the script is finished. So, all echos are collected by “onreadystatechange” and once the script sends an exit code the “onreadystatechange” sends what was echoed to whatever you setup to collect and parse the data.

Insert Function

As you can tell, our insert function will take three paramets which are the title, date, and link.

if ($TITLE != "" && $DATE != "" && $INFOLINK != "") {
    try {
        $serverPDO = new SQLite3('resources/server.db');
        $command = "INSERT INTO Movies VALUES('" . $TITLE . "','" . $DATE . "','" . $INFOLINK . "')";
        $serverPDO->exec($command);
        
        echo "<h2 style='width:100%;background-color:#0000ff;color:#ffffff;text-align:center;'>Inserted to db...</h2><br/>" .
        "Title: " . $TITLE . "<br/>Date: " . $DATE . "<br/>Link: " . $INFOLINK;
    } catch (Exception $e) {
        echo "<h2 style='width:100%; background-color:ff0000;color:#ffffff;text-align:center;'>Error! Database Insert Failed...</h2><br/>" . $e;
    }
} else {
    echo "<h2 style='width:100%; background-color:ff0000;color:#ffffff;text-align:center;'>Error!</h2><br/>" .
    "<h3>A field is empty...</h3>" . $e;
}

Lets break this down. The first parts are pretty much the same as the search function with the exception of execute than query being the command. We also confirm that each field is filled and if not we generate an error HTML markup. We have a try catch block if they are filled. In the try section, we connect to the database. We create a “command” of type string that inserts the sent data from the form. We then echo a success or failure message. Take note that this insert process is not AJAX. Our page will redirect to the process.php file and the file will output HTML. I’m doing it this way to show you two ways of processing data and why AJAX is useful in that we aren’t being redirected. As you can see, it’s a much cleaner user experience to use AJAX and this PHP example shows why. You can change this to AJAX but I will leave that to you to figure out how.

Conclusion

Discussion

We are DONE! Pat yourself on the back and get a cold beer or favorite beverage. You now have new possibilities available to you since you understand the basic concepts. Let’s do a quick recap and talk about pitfalls and the next steps one should take.

We start off by creating two files and one sub-folder. We then install our needed programs and a development environment. From there, we create our database in the sub-folder and the table in the database. It is important to recall that one of the fields is limited to a string size of 10. Anyway, we then entered some initial data so we could work with it after creating our code. After launching our PHP server, we create our initial HTML markup and talk about what we will do next. Next, we create our AJAX search script that checks against empties and so on. Since the HTML is done, we move on to the PHP. In the PHP, we check what’s sending the request and determine the necessary action from the POST data. We create our two functions and their logic which get called after the initial checks. Once the script exits, our AJAX sees this and we end the data to a function that then inserts the data to a div tag OR we get an HTML output in the case of the data insert form. We then drink our beverage and think about pitfalls and the next project we will do based off the work done here.

Pitfalls

The first massive pitfall is that we aren’t sanitizing our data. NEVER do a production project without cleaning input data! I skipped it here because I’m lazy and this article would get longer than I want it to. It can be pretty easy to do though since there are libraries out there one can use. You should use a JavaScript library or your own scripts to check the input. I recommend checking through the server too but the JavaScript should get most issues.

The next pitfall is that we aren’t checking the length of the date field. This can be done through JavaScript too and PHP can cover the process too. So, this would be one of the next steps to do as well as the above input sanitation.

The next pitfall is that the search function implements a poor query structure. I mentioned this before but we are collating things to keep in mind so I mention it here too.

I’m sure there are some other things of note but these three are the biggies. Let’s look at what our next steps might be with such a project.

Next Steps

    Here are some next steps to consider.

  • New Projects:
      • Use cookies to create a login system and account control to then access or create users for the database.
      • Use cookies and AJAX to create a tracking system that’ll insert data to the database about links clicked.
      • Create a meta search engine.
      • Create a password manager..
  • Improve Current Project:
      • Sanitize input fields to avoid exploits and future errors.
      • Implement a date field length check.
      • Make a better search system.

Result Images

ajax and php result
ajax and php result
ajax and php result 2
ajax and php result 2
error handling
error handling
error handling 2
error handling 2
db insert
db insert