Bart Simons

Compiling a LAMP stack for CentOS - Tutorial

 •  Filed under compiling, compile, LAMP, stack, CentOS

Getting the latest version of Apache, MySQL and PHP up and running on enterprise Linux operating systems can be a tough job. There are easy and quick ways to get around this, number 1 being the use of third-party repositories: but do you really want to use open-source software from third parties that might have been fiddled around with? I know, I can be a little bit paranoid about this. But, there is a second option: compiling the LAMP stack from source. This allows you to get control over:

  • The software versions used in the stack
  • The code that you compile (being able to review the code)
  • Enable and disable functionality that you (don't) need

Compiling the LAMP stack on CentOS from source is not that hard anymore, because I have written a script that automates the build process for you.

My script fetches all the source code that is needed to compile the LAMP stack and then compiles every dependency and/or program one by one. Afterwards, all the software gets installed in the /opt folder (you can always change this if you want).

So - without further ado - here's the script:

#!/bin/bash

TIMEFORMAT='It took %R seconds to complete this process.'  
time {  
    # Defining variables
    threads=$[$(nproc)+1]

    # Build local yum cache and install development tools
    echo "[1/16] Installing the 'Developer Tools' yum group.."
    yum -y makecache >/dev/null 2>&1 && yum -y groupinstall "Development Tools" >/dev/null 2>&1

    # Install other necessary binaries
    echo "[2/16] Installing necessary binaries.."
    yum -y install curl cmake >/dev/null 2>&1

    # Download source tarballs
    echo "[3/16] Downloading source tarballs.."
    curl ftp://xmlsoft.org/libxml2/LATEST_LIBXML2 -o libxml2.tar.gz >/dev/null 2>&1
    curl https://www.openssl.org/source/openssl-1.0.2l.tar.gz -o openssl.tar.gz >/dev/null 2>&1
    curl https://www.zlib.net/zlib-1.2.11.tar.gz -o zlib.tar.gz >/dev/null 2>&1
    curl http://apache.40b.nl/httpd/httpd-2.4.25.tar.gz -o httpd.tar.gz >/dev/null 2>&1
    curl https://ftp.pcre.org/pub/pcre/pcre-8.40.tar.gz -o pcre.tar.gz >/dev/null 2>&1
    curl http://apache.mirror.triple-it.nl/apr/apr-1.5.2.tar.gz -o apr.tar.gz >/dev/null 2>&1
    curl http://apache.mirror.triple-it.nl/apr/apr-util-1.5.4.tar.gz -o apr-util.tar.gz >/dev/null 2>&1
    curl https://ftp.gnu.org/gnu/ncurses/ncurses-6.0.tar.gz -o ncurses.tar.gz >/dev/null 2>&1
    curl https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-boost-5.7.18.tar.gz -o mysql.tar.gz -L >/dev/null 2>&1

    # Make source directories
    echo "[4/16] Creating source+build directories.."
    mkdir libxml2
    mkdir openssl
    mkdir zlib
    mkdir httpd
    mkdir pcre
    tar -xvzf httpd.tar.gz -C httpd --strip 1 >/dev/null 2>&1 && rm httpd.tar.gz
    mkdir httpd/srclib/apr
    mkdir httpd/srclib/apr-util
    mkdir ncurses
    mkdir mysql

    # Clone PHP sources
    echo "[5/16] Cloning PHP 7.1.5 from Github.."
    git clone -b php-7.1.5 https://github.com/php/php-src.git php7 >/dev/null 2>&1

    # Extract source packages
    echo "[6/16] Extracting source tarballs.."
    tar -xvzf libxml2.tar.gz -C libxml2 --strip 1 >/dev/null 2>&1 && rm libxml2.tar.gz
    tar -xvzf openssl.tar.gz -C openssl --strip 1 >/dev/null 2>&1 && rm openssl.tar.gz
    tar -xvzf zlib.tar.gz -C zlib --strip 1 >/dev/null 2>&1 && rm zlib.tar.gz
    tar -xvzf pcre.tar.gz -C pcre --strip 1 >/dev/null 2>&1 && rm pcre.tar.gz
    tar -xvzf apr.tar.gz -C httpd/srclib/apr --strip 1 >/dev/null 2>&1 && rm apr.tar.gz
    tar -xvzf apr-util.tar.gz -C httpd/srclib/apr-util --strip 1 >/dev/null 2>&1 && rm apr-util.tar.gz
    tar -xvzf ncurses.tar.gz -C ncurses --strip 1 >/dev/null 2>&1 && rm ncurses.tar.gz
    tar -xvzf mysql.tar.gz -C mysql --strip 1 >/dev/null 2>&1 && rm mysql.tar.gz

    # Pre-compile ncurses
    echo "[7/16] Compiling ncurses.."
    mkdir /opt/ncurses
    cd ncurses
    ./configure --prefix=/opt/ncurses --with-shared >/dev/null 2>&1 
    make -j$threads >/dev/null 2>&1 && make install >/dev/null 2>&1
    cd ..

    # Pre-compile mysql
    echo "[8/16] Compiling MySQL.."
    mkdir /opt/mysql
    cd mysql
    cmake -DWITH_BOOST=boost/ -DCMAKE_INSTALL_PREFIX:PATH=/opt/mysql -DCURSES_LIBRARY=/opt/ncurses/lib/libncurses.so -DCURSES_INCLUDE_PATH=/opt/ncurses/include . >/dev/null 2>&1
    make -j$threads >/dev/null 2>&1 && make install >/dev/null 2>&1
    cd ..

    # Pre-compile openssl
    echo "[9/16] Compiling OpenSSL.."
    mkdir /opt/openssl
    cd openssl
    ./config --prefix=/opt/openssl -fPIC >/dev/null 2>&1
    make -j$threads >/dev/null 2>&1 && make install >/dev/null 2>&1
    cd ..

    # Pre-compile libxml2
    echo "[10/16] Compiling LibXML2.."
    mkdir /opt/libxml2
    cd libxml2
    ./configure --without-python --prefix=/opt/libxml2 >/dev/null 2>&1
    make -j$threads >/dev/null 2>&1 && make install >/dev/null 2>&1
    cd ..

    # Pre-compile pcre
    echo "[11/16] Compiling PCRE.."
    mkdir /opt/pcre
    cd pcre
    ./configure --prefix=/opt/pcre >/dev/null 2>&1
    make -j$threads >/dev/null 2>&1 && make install >/dev/null 2>&1
    cd ..

    # Pre-compile zlib
    echo "[12/16] Compiling zlib.."
    mkdir /opt/zlib
    cd zlib
    ./configure --prefix=/opt/zlib >/dev/null 2>&1
    make -j$threads >/dev/null 2>&1 && make install >/dev/null 2>&1
    cd ..

    # Compile httpd
    echo "[13/16] Compiling httpd.."
    mkdir /opt/httpd
    cd httpd
    ./configure --with-pcre=/opt/pcre --with-z=/opt/zlib --with-libxml2=/opt/libxml2 --with-ssl=/opt/openssl --with-included-apr --enable-ssl --prefix=/opt/httpd >/dev/null 2>&1
    make -j$threads >/dev/null 2>&1 && make install >/dev/null 2>&1
    cd ..

    # Compile PHP7
    echo "[14/16] Compiling PHP7.."
    mkdir /opt/php7
    cd php7
    ./buildconf --force >/dev/null 2>&1 && ./configure --with-apxs2=/opt/httpd/bin/apxs --prefix=/opt/php7 --with-libxml-dir=/opt/libxml2 >/dev/null 2>&1
    make -j$threads >/dev/null 2>&1 && make install >/dev/null 2>&1
    cd .

    # Cleanup time!
    echo "[15/16] Cleaning up.."
    rm -rf php7 && rm -rf httpd && rm -rf zlib && rm -rf pcre && rm -rf libxml2 && rm -rf openssl && rm -rf mysql && rm -rf ncurses

    echo "[16/16] Finishing configuration for httpd, PHP7 and MySQL.."

    useradd -s /sbin/nologin mysql
    mkdir /opt/mysql/data
    chown -R mysql:mysql /opt/mysql/data
    mkdir /opt/mysql/data

    echo ""
    echo "Initializing MySQL:"
    echo ""

    /opt/mysql/bin/mysqld --initialize --datadir=/opt/mysql/data --user=mysql

    echo ""
    echo "You can start the MySQL daemon with:"
    echo "/opt/mysql/bin/mysqld --user=mysql --datadir=/opt/mysql/data --socket=/opt/mysql/data/mysql.sock"
    echo ""

    useradd -s /sbin/nologin www-data
    chown -R www-data:www-data /opt/httpd/htdocs
    sed -i 's/User daemon/User www-data/g' /opt/httpd/conf/httpd.conf
    sed -i 's/Group daemon/Group www-data/g' /opt/httpd/conf/httpd.conf

    mkdir /opt/certificates
    openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /opt/certificates/selfsigned.key -out /opt/certificates/selfsigned.crt -subj "/C=NL/ST=Zuid-Holland/L=Dordrecht/O=bartsimons.me/OU=IT Department/CN=bartsimons.me" >/dev/null 2>&1
    currentdate=$(date)
    echo "" >> /opt/httpd/conf/httpd.conf
    echo "# Appended at: ${currentdate}" >> /opt/httpd/conf/httpd.conf
    echo "LoadModule ssl_module modules/mod_ssl.so" >> /opt/httpd/conf/httpd.conf
    echo "<FilesMatch \.php$>" >> /opt/httpd/conf/httpd.conf
    echo "  SetHandler application/x-httpd-php" >> /opt/httpd/conf/httpd.conf
    echo "</FilesMatch>" >> /opt/httpd/conf/httpd.conf
    echo "Listen 443" >> /opt/httpd/conf/httpd.conf
    echo "<VirtualHost *:443>" >> /opt/httpd/conf/httpd.conf
    echo "  SSLEngine on" >> /opt/httpd/conf/httpd.conf
    echo "  SSLCertificateFile /opt/certificates/selfsigned.crt" >> /opt/httpd/conf/httpd.conf
    echo "  SSLCertificateKeyFile /opt/certificates/selfsigned.key" >> /opt/httpd/conf/httpd.conf
    echo "</VirtualHost>" >> /opt/httpd/conf/httpd.conf

    echo "You can start the HTTPD daemon with:"
    echo "/opt/httpd/bin/httpd"
    echo ""
    echo "Done!"
    echo ""
    echo ""
}

This has been tested on CentOS 7 x64.

You can start MySQL with this command:

/opt/mysql/bin/mysqld --user=mysql --datadir=/opt/mysql/data --socket=/opt/mysql/data/mysql.sock

And you can start httpd with this command:

/opt/httpd/bin/httpd

Should you run into an issue: feel free to leave a comment!

Creating HTML tables from JSON data in JavaScript

 •  Filed under json, data, html tables, javascript

A few weeks ago I have written a simple JavaScript library to convert JSON data to an HTML table, and vice versa if you need it. With that library comes even more functionality, like the ability to filter (search) through table rows and the ability to filter JSON data for a multi-page table layout.

You can find my project on GitHub.

This is the table and search box HTML code that I used for this article:

<div class="container">  
  <div class="row">
    <br>
    <input type="text" name="searchbox" id="searchbox" style="width: 100%;"><br><br>
  </div>

  <div class="row">
    <table id="userTable" class="table">
      <thead>
        <tr>
          <th>ID</th>
          <th>Name</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>1</td>
          <td>Bart</td>
       </tr>
        <tr>
          <td>2</td>
          <td>Nick</td>
        </tr>
        <tr>
          <td>3</td>
          <td>Jason</td>
        </tr>
        <tr>
          <td>4</td>
          <td>Fred</td>
        </tr>
        <tr>
          <td>5</td>
          <td>Ed</td>
        </tr>
        <tr>
          <td>6</td>
          <td>Peter</td>
        </tr>
      </tbody>
    </table>
  </div>
</div>  



So let's dive deeper into some code examples that you can use to create your tables from JSON data:


Example 1: Convert an HTML table to JSON

$(document).ready(function()
{
  // Create a new JSONTable Object from the basicTable table.
  var jsonTable = new JSONTable($("#basicTable"))

  // Convert existing HTML table to a JSON object.
  var tableData = jsonTable.toJSON()
})



Example 2: Search through a table with the filter function

$(document).ready(function()
{
  // Create a new JSONTable Object from the basicTable table.
  var jsonTable = new JSONTable($("#basicTable"))

  // Convert existing HTML table to a JSON object.
  var tableData = jsonTable.toJSON()

  // Create a jQuery event handler on the searchbox.
  $("#searchbox").on('input', function(e) {
    jsonTable.filter($(this).val())
  })
})



Example 3: Create a new HTML table directly from JSON data

// Build a JSON object array with items which are to be included in the table.
var jsonData = [{"ID":"1","Name":"User1"},{"ID":"2","Name":"User2"},{"ID":"3","Name":"User3"},{"ID":"4","Name":"Admin1"},{"ID":"5","Name":"Admin2"}]

// Create a new table inside the body tag
$("body").append("<table id='testTable'></table>")

// Spawn a new JSONTable object on the newly created table
var jsonTable = new JSONTable($("#testTable"))

// Create HTML table (data)structure from JSON data
jsonTable.fromJSON(jsonTest)  



You should definitely try these examples. Good luck!

Detect and monitor DOM changes with MutationObserver

 •  Filed under monitor, javascript, detect, dom changes, mutationobserver

The MutationObserver JavaScript API allows a developer to actively watch for DOM changes, so that if something gets changed, added or removed within the boundaries of the specified DOM node, a callback function will be triggered.

Browser support for this API is pretty good as well. All major modern browsers do support MutationObserver, but please note that IE10 and lower are not supported unless you use some sort of shim or polyfill for this.

Getting started is very easy as well:

// Step 1: Create a new MutationObserver object
var observer = new MutationObserver( function(mutations) { // this is the callback function } )

// Step 2: Observe a DOM node with the observer as callback
observer.observe(document.querySelector("table"), { attributes: true, childList: true, attributeOldValue: true })  



As an example I have built up a table to watch out for DOM changes:

<table id="demoTable" class="table">  
  <thead>
    <tr>ID</tr>
    <tr>E-mail</tr>
  </thead>

  <tbody>
    <tr>
      <td>1</td>
      <td>todd@localhost</td>
    </tr>
    <tr>
      <td>2</td>
      <td>ted@localhost</td>
    </tr>
    <tr>
      <td>3</td>
      <td>root@localhost</td>
    </tr>
    <tr>
      <td>4</td>
      <td>bart@localhost</td>
    </tr>
  </tbody>
</table>  



And here is the JavaScript code that goes with this:

var observer = new MutationObserver(function(mutation) {  
console.log(mutation)  
})

var observerConfig = {  
  attributes: true,
  childList: true,
  attributeOldValue: true,
  characterData: true
}

const tableRows = document.querySelectorAll("#appUsers tr")

for (i = 0; i < tableRows.length; i++)  
{
  observer.observe(tableRows[i], observerConfig);
}



Try to destroy, add or recreate td elements inside the table and you will get an array of MutationRecord objects returned within your browsers' console. Please note that when you edit the node's innerHTML, nothing will get triggered. I don't know if this is a bug in Safari (I only tested this in Safari, FYI) or something by design.

Using MySQL in Swift with Perfect

 •  Filed under swift, mysql, perfect

So I recently got a chance to play around with Perfect - a "web app framework" for Swift that provides you with multiple building blocks to get your project going. One of the really neat things about this framework is that it contains anything you need to get stuff connected. I came across their MySQL library that can be used in projects with or without the other Perfect dependencies involved. You can't get any more modular than this!


My development environment

I tend to always use Linux for my projects, and this little project is no exception. My dev box is equipped with the following stuff:

  • Ubuntu Server 16.04 LTS
  • MySQL Server
  • Swift 3.0.2

You also need to install the libmysqlclient-dev package through apt-get in order to use and build the Swift MySQL package.


Creating a new project

Create a new directory for this project on your server. I called mine mysql-app. Change your current directory to that directory and run swift package init --type executable to generate a blank Swift project. If you have a Mac and plan to use Xcode for your project: you can initialize an Xcode project file with swift package generate-xcodeproj


Adding Perfect-MySQL to the project

Edit your Package.swift file and include Perfect-MySQL as a dependency, like this:

import PackageDescription

let package = Package(  
    name: "mysql-app",
    dependencies: [
        .Package(url: "https://github.com/PerfectlySoft/Perfect-MySQL.git", majorVersion: 2)
    ]
)

Now it's time to write some code!


The database structure


The code

Just put the following code inside Sources/main.swift:

import MySQL

let sqlHost     = "127.0.0.1"  
let sqlUser     = "app_authentication"  
let sqlPassword = "testing01"  
let sqlDB       = "app_authentication"

func fetchData()  
{
    let mysql   = MySQL()
    guard mysql.connect(host: sqlHost, user: sqlUser, password: sqlPassword, db: sqlDB) else
    {
        print(mysql.errorMessage())
        return
    }

    defer {
        mysql.close()
    }

    let theStatement = MySQLStmt(mysql)

    _ = theStatement.prepare(statement: "SELECT * FROM users")
    _ = theStatement.execute()

    let theResults = theStatement.results()

    print("\r\n")

    _ = theResults.forEachRow {
        e in

        for i in 0..<e.count {
            let theFieldName = theStatement.fieldInfo(index: i)!.name
            print("\(theFieldName): \(e[i]!)")
        }

        print("\r\n")
    }
}

fetchData()  


Build and run

Just run swift build to build your project and run .build/debug/mysql-app to run your application. It should return this as the output in your terminal:


Extra information

I made this small tutorial after I had to fiddle around with this library for one whole day. The documentation suggests to use mysql.query to run queries, but there's too little information available about running prepared statements. Not only in the documentation of Perfect, but also on the whole web. Then - a couple hours later - I discovered the MySQLStmt class, after digging into the Swift Tests available on their Github repo.

Another reason to only use the MySQLStmt class is because the class contains a function called fieldInfo which returns the name of a column by ID. mysql.query simply doesn't have that...

Oh well, at least I got some of my code fixed today. Enjoy programming in Swift!

Controlling iTunes via Swift using SBApplication

 •  Filed under swift, itunes, sbapplication, scriptingbridge

Since I took my hands down on Swift, I discovered SBApplication, Apple's take on making scriptable calls to the applications you already have on your computer. Want to get a list of currently opened tabs in Safari, and each of their titles? No problem!

I used tingraldi's SwiftScripting repository to generate Swift headers for any application that is scriptable. The generated headers give you full access to all the available calls you can make to a scriptable application.

I came up with an idea that might be great for demoing the purposes of the SBApplication class: a simple command-line application that controls and/or fetches information from and to iTunes. I uploaded my code as a Github repository, it should work for any Intel-based Mac.

https://github.com/bmsimons/itunescli

The how-to-use and build guide can be found inside the readme file on my repository.