PHP Developer Guide For Modern Web Development Workflow Setup

Murat Gözel
Code with Benefit
Published in
8 min readApr 10, 2018
Modern Web Development Workflow

I have prepared this guide as a reference for php developers who want to switch from ftp (or sftp) to git (version based) based development.

Fundamental topics including cloud server setup and configuration, local server setup and configuration, git service integration covered in this article.

This guide is more like a general reference of modern web development workflow rather than deep dive into features. Please search certain commands and features mentioned here to better understand and to build better architecture.

If you don’t have a UNIX based computer and UNIX based cloud server, this guide may not suit you well. MACOS as local server and Ubuntu 16 as cloud server used throughout this guide.

1. Local Server Setup and Configuration

We need one basic thing in order to start developing our web app and access it from our browser.

  1. PHP
  2. Composer for PHP dependency management (Optional)
  3. MYSQL or any other database (Optional)
  4. Memcached or any other in memory key-value store (Optional)
  5. Watchman or any other file watching service (Optional)

PHP

You can find if php already exists in your system by typing php -v in your terminal. If it doesn't exist or you want to install the latest version of php (which is 7.x currently) you can install it with homebrew by typing brew install php in your terminal.

We are not going to install any web server such as apache or nginx since php’s built-in development server works very well.

cd /path/to/my/project
php -S localhost:3000

By executing this command, PHP start accepting web requests through port 3000 and serves your php files pretty much like apache or nginx does.

You can now start writing your php scripts and access them through your browser by typing http://localhost:3000/index.php in your browser's address bar. Or http://localhost:3000/home if you have a router written in php.

Today’s development workflows has many enhancing tools to make coding more productive. Following tools mentioned in this section is just to make your workflow more productive.

Composer

Setting up Composer is easy as by typing brew install composer in your terminal. Once you set it up, you can use any dependency from packagist in your php development server seamlessly.

MYSQL

Go to the MYSQL official website, enter the Downloads section, choose Community Tab and click MYSQL Community Server link. You will find the download link according to your OS. It is easy to install.

You may also need the official GUI tool for MYSQL databases, MYSQL Workbench. Definitely recommend it.

Memcached

Memcached is in memory key-value store. Which means, what you set in memcached store, will exist until memcached server stop or restart. This is very useful for things that your app gets by making complex calculations across requests.

Memcached is a stand alone program and we need to enable its php extension in order to work with our app seamlessly.

How to install Memcached and PHP Extension on MacOS?

# Install memcached
brew install memcached
# Start memcached server
memcached -p 11211
# Install Memcached PHP extension
brew install php70-memcached
# igbinary module required by Memcached
brew install php70-igbinary

Memcached server is online and ready to store our data but we first need to enable Memcached and igbinary PHP extensions.

PHP extensions can be enabled by placing them into the php.ini file.

Let’s learn which php.ini file our development server is using.

Place the code phpinfo(); in some file in your app and view it in your browser. You will see that all configuration parameters and values belong to the running PHP program are in your screen. Search for a line for php.ini in your browser screen and you will see there is a matching line which is saying "Loaded configuration file". It's value is the php.ini file’s absolute path your development php server use.

Before placing extension directives into the php.ini file we need to look for their absolute paths:

find /usr -name memcached.so
# Outputs something like this: /usr/local/Cellar/php7X-memcached/3.X.X/memcached.so
find /usr -name igbinary.so
# Outputs something like this: /usr/local/Cellar/php7X-igbinary/2.X.X/igbinary.so

Edit php.ini file:

sudo nano /etc/php.ini
# Place extension absolute paths in your php.ini file
extension=/usr/local/Cellar/php7X-igbinary/2.X.X/igbinary.so
extension=/usr/local/Cellar/php7X-memcached/3.X.X/memcached.so
# Save and exit from the file.

Stop your development server by typing CTRL + C and start again. You can see in your phpinfo(); output whether memcached enabled successfully or not.

Watchman

A file watching service can dramatically increase your productivity by auto refreshing your browser and auto compiling your code. I’m using Facebook’s watchman but any other service satisfy you essentially.

Here is an example i am using in my workflow:

watchman-make -p '*.php' '**/*.styl' --run /path/to/my/project/compile_reload_browser.sh

This code is watching files ending with php and styl. It makes compilations and reloads the browser's localhost tab whenever detects a change in those files.

2. Cloud Server Setup and Configuration

Basic tools are covered in this section in order to create a working http server.

Buy A Ubuntu 16 Server Instance from one of the cloud server service providers. Digitalocean in my case.

Configure How You Sign In To The Server

Digitalocean send you an email that contains root password. Open your terminal and type ssh root@YOUR_SERVER_IP to login your server. Enter your password and configure public-private key authentication if you want.

# Create a new user with sudo permissions
adduser bob
usermod -aG sudo bob

It is recommended to set public-private key authentication for this user too.

Fundamental Services

Following services are fundamental and should be installed in advance:

# Apache web server
sudo apt-get update
sudo apt-get install apache2 -y
sudo service apache2 restart
# MYSQL
sudo apt-get install mysql-server -y
# PHP
sudo apt-get install python-software-properties -y
sudo add-apt-repository ppa:ondrej/php -y
sudo apt-get update
sudo apt-get install php7.2 -y
sudo apt-get install php7.2-mbstring php7.2-mysql php7.2-xml php7.2-curl php7.2-gd php7.2-pdo-mysql php7.2-xml php7.2-xsl -y
# Certbot - Let's Encrypt SSL Client
sudo add-apt-repository ppa:certbot/certbot -y
sudo apt-get update
sudo apt-get install python-certbot-apache -y
# Composer
sudo nano composer-setup.sh # contents is in the gist below
sudo bash composer-setup.sh
sudo mv composer.phar /usr/local/bin/composer
# Install ZIP and UNZIP. Using it for backup.
sudo apt-get install zip unzip -y

composer-setup.sh

https://gist.github.com/muratgozel/be3cdb7396b5ce429c96561fb097b87c

Configure web server directory permissions:

sudo nano /etc/apache2/envvars
# Add "umask 002" to the end of the file. Save and exit.
# Add our current user bob to the www-data group.
sudo usermod -aG www-data bob
# Change the group owner of the directory /var/www
sudo chgrp -R www-data /var/www
# Every user who belongs to www-data group have read and write access to the everything inside /var/www
sudo chmod 2770 /var/www

Create and activate apache virtual host file in order to make our web app directory readable across web:

sudo nano /etc/apache2/sites-available/example.com.conf # contents is in the gist below.
sudo a2ensite example.com.conf
sudo service apache2 reload

example.com.conf

https://gist.github.com/muratgozel/d5e16ecd8a799a25a4dd49ec49f35c73

What do you think about privacy? There is an easy and powerful solution for that:

# Configure SSL
sudo certbot --apache -d example.com -d www.example.com

Our web app is now accessible over web.

We now have a local server and a cloud server. We want to be able to push the code changes in the local server to the cloud server fast and seamlessly.

3. GIT Integration

A Gitlab will be used in this article but many GIT service providers have similar ways in updating cloud codebase.

Repository

A repository is a central location of the app’s codebase. Any change made by anyone, should be pushed to the repository. Cloud server should automatically fetch these changes in order to create a productive workflow.

Create a private repository. Such as web-app.

Get the SSH endpoint. Will be something like git@gitlab.com:web-app.git

Configure Local Server

What we did below is to configure the local computer to push code changes to the repository we have just created above.

# Configure GIT
git config --global user.name "Firstname Lastname"
git config --global user.email username@email.com
# Activate GIT in your app
cd /path/to/my/project
git init
# Configure to push your changes to the repository you've just created.
git remote add origin git@gitlab.com:web-app.git
# Create a production branch.
# We want cloud server to be updated only if production branch changes.
git checkout -b production
# Send everything in your project to the repository
git add * && git commit -m "Added XYZ feature"
git push -u origin production

Code in our local server have been sent to the repo. Now on, every time we did changes in the codebase, we are going to execute:

git add *
git commit -m "Added ABC feature"
git push

If Gitlab asking you a password in every push, you may better configure SSH authentication between your computer and Gitlab. Gitlab has a good documentation for that.

Configure Cloud Server

What we did below is to configure the cloud server to fetch code changes in the repository.

Make sure you have set up SSH authentication between your server and Gitlab. Again, Gitlab has a good documentation for that.

Download all files in the app to the cloud server:

cd /var/www
git clone git@gitlab.com:web-app.git

Now on, every time code changed in the repository’s production branch, the following commands has to be executed:

cd /var/www/web-app
git reset --hard origin/production
git pull

What commands above do is deploying. It fetches updates from the repository and updates the live folder accessible over the web.

This is seamless deployment for our app but it is not fast. Every time we push in our local computer to the repository, we need to connect our server and execute the commands above.

Auto-Deploy

Web app, fetches the changes automatically in the production branch of the repository whenever we push to the production branch from our local computer.

  1. Configure A Webhook
  2. Configure SSH Authentication Between Apache User and Gitlab
  3. Create A Deploy Script

A Webhook

A webhook is the way of telling “send request to this URL when this happens in a repository” in the Git Service.

In Gitlab, go to project Settings — Integrations page.

Create a new webhook by entering your preferred url (such as https://example.com/deploy.php), a random string (such as “as9s2pd7sdhs5”) and choosing only the “Push Events” trigger.

We have created a webhook. But we need a real working deploy script located in that path.

SSH Authentication Between Apache User and Gitlab

Apache user need to be able to fetch the code changes from the repository because deploy script is run by apache.

Login to the cloud server and generate public-private key pair for the www-data user.

# Create public-private key pair for www-data user.
sudo -u www-data ssh-keygen -t rsa -b 2048 -P ""
# Print public key to the screen and copy it
sudo cat /var/www/.ssh/id_rsa.pub

Now on Gitlab, go to project Settings — Repository page. Expand Deploy Keys and paste the public key you have just copied into the Key field.

Turn back to cloud server and approve authenticity of Gitlab:

cd /var/www/web-app
sudo -u www-data git pull

Apache user is now able to get data from the repository.

Deploy Script

The deploy script below, is not ready for production. Take the necessary precautions and make it live on the path you specified while creating the webhook.

deploy.php

define('GITLAB_TOKEN', 'as9s2pd7sdhs5');
define('GITLAB_BRANCH', 'production');
if ($_SERVER['HTTP_X_GITLAB_TOKEN'] != GITLAB_TOKEN) {
header($_SERVER['SERVER_PROTOCOL'].' 400 Bad Request.', true, 400);
die();
}
$output = shell_exec('cd /var/www/web-app && git reset --hard origin/'.GITLAB_BRANCH.' && git pull 2>&1');header($_SERVER['SERVER_PROTOCOL'].' 200 Ok', true, 200);

On cloud server:

cd /var/www/web-app
nano deploy.php
# Paste the contents of your deploy script, save and exit.

Gitlab will send a request to the deploy script whenever someone pushes the code to the production branch and app will automatically update its live codebase.

🎩

--

--

Murat Gözel
Code with Benefit

Freethinker / Maker / Software Developer / Designer / Advertiser