Blog

Deploy Node.js app on heroku

Signup/Signin on heorku

https://herokuapp.com/

Login from terminal (Make sure you have installed heroku cli – https://devcenter.heroku.com/articles/heroku-cli#download-and-install)

heroku login

Create app.js

const express = require("express");
const app = express();
const port = 8080;

app.get("/", (req, res) => {
    res.send("Hello Heroku");
})

app.listen(process.env.PORT || port, () => {
	console.log("listening 8080...");
});

process.env.PORT this will be provided by heroku server

Test locally by running following command

node app.js
OR
nodemon app.js

If you get any error e.g. module not found you can install those module using npm

npm install <module_name>

To find installed module version

npm view <module_name> version
e.g.
npm view express version

Create package.json

{
	"scripts" : {
		"start" : "node app.js"
	},
	"dependencies": {
		"express": "4.17.1",
		"mongoose": "5.13.3",
		"cors": "2.8.5"
	}
}

Run following command from terminal

#onetime
git init
#onetime
heroku create <yournewappname>

Run git commands

git add .
git commit -m 'msg'

#to verify origin
git config -l

#if you are not able to see url and fetch then run git remote add origin 
#remote.heroku.url=https://git.heroku.com/project.git
#remote.heroku.fetch=+refs/heads/*:refs/remotes/heroku/*
#git remote add origin heroku_git_url
#git push origin master

git push heroku master

Once app is deployed it will show you an url which you can access publicly from internet.

To see error logs

heroku logs --tail

Nginx

create project and verify with normal url

mkdir /var/www/html/myproject

vim index.html

<h1>Hello World</h1>

vim index.php

<?php

phpinfo();

Create server block conf file

vim /etc/nginx/conf.d/myproject.conf

server {
  listen 8082 default_server;
  server_name _;

  index index.php index.html;

  root /var/www/html/myproject;

  location ~ \.php$
  {
      include snippets/fastcgi-php.conf;
      fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
  }
}

Test nginx configuration

nginx -t

restart nginx

sudo service nginx restart
OR
sudo systemctl restart nginx

For Laravel Project
Specify path till public directory

Laravel Framework

Install required packages

sudo apt-get update
sudo apt-get install php-mbstring
sudo apt-get install php-curl
sudo apt-get install php-xml

Install Laravel via composer

composer create-project laravel/laravel example-app
composer install

php artisan --version
php artisan serve

Generating app key

php artisan key:generate 
php artisan key:generate --show

Redis

Redis Playground

https://try.redis.io/

Note: This try redis io is community version on web so few commands might not work. To use redis’s full power you can download and install on your local system


Redis is an in-memory data structure store, used as a distributed, in-memory key–value database, cache and message broker, with optional durability. Redis supports different kinds of abstract data structures, such as strings, lists, maps, sets, sorted sets, HyperLogLogs, bitmaps, streams, and spatial indices.

Installation

To install redis on windows download msi package from here
https://github.com/microsoftarchive/redis/releases/

For Linux Distr

sudo apt-get install redis-server

To install PHPRedis client use following command

sudo apt-get install php-redis
#for specific version
sudo apt-get install php7.4-redis

To verify redis installed in your system
Note: On windows you might need to add redis exe path in environment variables

redis-cli PING

To see all keys

KEYS *

DATATYPES

  • string
  • list
  • set
  • sorted set
  • hash
  1. String
    Syntax to set string value
SET key value [EX seconds] [PX milliseconds] [NX|XX]

To set only string value

SET keyname value

To check whether key exist or not

EXISTS keyname

Get key’s value

GET keyname

To delete any specific key

DEL keyname

To delete all keys

FLUSHALL

SET string with expiry

SET key value
EXPIRE key expiry-time-in-seconds
#shortcut
SET key value EX expiry-time-in-seconds

To check expiry time of any key

TTL key

SET string values using key:spaces
This is required when you want to set values related to one entity

SET key:space value

2. List or Stack

To set list use LPUSH

LPUSH key value1
LPUSH key value2
LPUSH key value3
OR
LPUSH key value1 value2 value3

To get length of list

LLEN key

To access any value of list you need to use LRANGE

LRANGE key from-index to-index

Use -1 in to-value to get all elements from list

LRANGE key 0 -1

To get specific index value
NOTE this will act like stack so LIFO algorithm will apply here i.e. index 0 will give you last inserted/pushed value

LINDEX key 0

LPUSH and RPUSH (left and right push)

LPUSH key value
RPUSH key value

LPOP and RPOP

LPOP key
RPOP key

Remove specific element from list

LREM key count value

3. Sets

Set is similar to list the main difference is it does not allow duplicate members
Order is not maintained in set

To add member in sets

SADD key value1 value2 value3

To view members of sets

SMEMBERS key

To remove member from sets

SREM key member

To get length of Sets

SCARD key

Compare Sets

SINTER set1 set2
SDIFF set1 set2
SUNION set1 set2

4. Sorted Sets

Sorted set are similar to sets the major difference is it stored members based on score i.e. sorted by score

ZADD key score member

To add multiple members

ZADD key rank1 member1 rank2 member2

To get count of sorted sets

ZCOUNT key

To See all members of sorted sets

ZRANGE key 0 -1

To get rank(index) of specific member

ZRANK key member

To get score of specific member

ZSCORE key member

To remove member from sorted sets

ZREM key member

5. Hashes

Hash is used to set field value pair it is similar to associative array

To set hash

HGET key field1 value1
HGET key field2 value2

To get field value

HGET key field

To get all field values

HGETALL key

To get length of hash key

HLEN key

To add field values at once

HMSET key field1 value1 field2 value2 field3 value3

To get values at once

HMGET key field1 field2 field2

To delete specific field from hash

HDEL key field1 field2

Assignment (set and get values of each type)

  1. Create string name age and city and set value in it
  2. Create List of fruits, weekdays, planets and set values in it
    Print length and values of list
  3. Create Sets of employees and managers
    Print length and values of Sets
  4. Create Hash record1, record2, record3 and add fields name age city in each hash
    Print length and values of each hash

Reference Links

User Group and Permission

User

List all users

cat /etc/passwd

List specific user

cat /etc/passwd | grep username
OR
grep username /etc/passwd

Create new user

useradd username

Delete existing user

userdel username

Set user password or update password

passwd username

You can use shortcut to add new user. Using following command you can create user set password and create home directory for newly added user

adduser username
ls -l /home/username

Rename existing user

usermod --login new-name old-name

Group

List all groups

cat /etc/group

List specific group

cat /etc/group | grep groupname
cat /etc/group | grep ^groupname
grep groupname /etc/group
grep ^groupname /etc/group

Add new group

groupadd group-name

Delete existing group

groupdel group-name

List all members of specific group

getent group group-name

Add new member in specific groups

usermod -a -G group-name1,group-name2,... user-name

Check in which groups user exist

groups user-name

Remove user from specific group

gpasswd -d user-name group-name

Permission

LIST FILES AND DIRECTORIES

OWNER – FIRST 3 FLAGS SHOWS OWNER’S PERMISSION

GROUP- MIDDLE 3 FLAGS SHOWS GROUP’S PERMISSION

OTHERS- LAST 3 FLAGS SHOWS OTHER’S PERMISSION

Permission List

  • 7 – 111 => read write execute
  • 6 – 110 => read write –
  • 5 – 101 => read – execute
  • 4 – 100 => read – –
  • 3 – 011 => – write execute
  • 2 – 010 => – write –
  • 1 – 001 => – – execute
  • 0 – 000 => no permission

How to change permission

chmod -Rf 777 path-to-file-or-directory

How to give only specific permission

#only executable
chmod -Rf +x path-to-file-or-directory

#only writable
chmod -Rf +w path-to-file-or-directory

#only readable
chmod -Rf +r path-to-file-or-directory

How to give permission to only specific role

#only owner
chmod -Rf u+x path-to-file-or-directory

#only group
chmod -Rf g+x path-to-file-or-directory

#only others
chmod -Rf o+x path-to-file-or-directory

Ownership

FIRST FLAG IN ROLE IS FOR OWNER

SECOND FLAG IN ROLE IS FOR GROUP

How to change ownership of any file or directory

chown -Rf user:group path-to-file-or-directory

Change attribute read only

chattr +a file.txt
  • chattr: This is a command in Linux used to change file attributes on a file system.
  • +a: This option sets the “append-only” attribute on the specified file. When this attribute is set, the file can only be opened in append mode for writing. Existing data in the file cannot be modified or removed. This attribute is often used to prevent accidental deletion or modification of important files.
  • to revert use -a option for chattr

Namespaces

What are namespaces?

Namespaces are a way of encapsulating items.
e.g. In any operating system directories serve to group related files, and act as a namespace for the files within them.

foo file in abc lmn pqr and xyz directory

As a concrete example, the file foo.txt can exist in all 4 directories with different contents in each.

Similarly to avoid ambiguity in PHP we have namespaces. Namespaces solve the confusion of having same class name in program.

Let’s understand this with example.

AdminAccount.php

<?php

class AdminAccount {
        public function __construct() {
                echo "Admin Account Controller..." . PHP_EOL;
        }
}

UserAccount.php

<?php

class UserAccount {
        public function __construct() {
                echo "User Account Controller..." . PHP_EOL;
        }
}

index.php

<?php

require("UserAccount.php");
require("AdminAccount.php");

new UserAccount();
new AdminAccount();

Now, what if we have the same class name in both files.
This scenario always comes when you use third-party libraries or any framework.

AdminAccount.php

<?php
class Account {
        public function __construct() {
                echo "Admin Account Controller..." . PHP_EOL;
        }
}

UserAccount.php

<?php
class Account {
        public function __construct() {
                echo "User Account Controller..." . PHP_EOL;
        }
}

index.php

<?php

require("UserAccount.php");
require("AdminAccount.php");

new Account();
new Account();

This will create confusion about which instance to be created.
Now let’s resolve this problem using namespaces.

AdminAccount.php

<?php
namespace Admin;

class Account {
        public function __construct() {
                echo "Admin Account Controller..." . PHP_EOL;
        }
}

UserAccount.php

<?php
namespace User;

class Account {
        public function __construct() {
                echo "User Account Controller..." . PHP_EOL;
        }
}

index.php

<?php

require("UserAccount.php");
require("AdminAccount.php");

new User\Account();
new Admin\Account();
script output
directory structure

PHPUnit

To install phpunit framework make sure you have installed composer
If not follow instructions from this link http://codeinsightacademy.com/blog/php/composer/

Installation

Install php-xml
As we are going to use phpunit.xml we need to install php-xml

sudo apt install php-xml
#To install specific version
sudo apt install php7.4-xml

Install mbstring

sudo apt-get install php-mbstring

Create composer.json file in project root directory

{
"autoload" : {}
}

Run one of the composer command

composer dump-autoload -o
OR
composer update

Install sluggable

composer require cviebrock/eloquent-sluggable

Install intl
This is required when you are using Code Igniter framework

apt-get install php-intl
#OR specific version
apt-get install php7.4-intl

Install php unit framework

composer require phpunit/phpunit ^9

Create function

global_functions.php

<?php

function add($x = 0, $y = 0) {
        return $x + $y;
}

index.php

<?php

require_once("vendor/autoload.php");

echo add(5, 6);

composer.json

{
    "autoload": {
            "files": ["global_functions.php"]
    },
    "require": {
        "cviebrock/eloquent-sluggable": "^8.0",
        "phpunit/phpunit": "^9"
    }
}

Run index.php file

php index.php

Write Testcase

phpunit.xml

<?xml version="1.0" encoding="UTF-8"?>

<phpunit bootstrap = "vendor/autoload.php"
 colors = "true">
    <testsuites>
        <testsuite name="Sample test suite">
            <directory>tests</directory>
        </testsuite>
    </testsuites>

</phpunit>

tests/GlobalFunctionsTest.php
NOTE: MAKE SURE TO GIVE test PREFIX TO YOUR TEST FUNCTION

<?php

class GlobalFunctionsTest extends \PHPUnit\Framework\TestCase {
        public function testAdd() {
                $result = add(5, 6);
                $this->assertEquals(11, $result);
        }
}

Get all assertions functions from here
https://phpunit.readthedocs.io/en/9.5/assertions.html

Run TestCase from root directory

./vendor/bin/phpunit
testcase output
./vendor/bin/phpunit --testdox
output with function names and result

project directory structure

tree -I "vendor"

Parse ini file

What is INI file

An INI file is a configuration file for computer software that consists of a text-based content with a structure and syntax comprising key–value pairs for properties, and sections that organize the properties.

parse_ini_file function

Parse ini file is a function to parse any configuration file which has key-value pair
This is required when you want to keep all application-level configuration parameters in one place
Maintaining configuration level parameter/variables is easy when you use ini file
You need to make changes in one file and it will reflect changes throughout the application


Syntax

parse_ini_file(file, process_sections, scanner_mode)

myapp.ini

#comment goes here

APP_NAME	= UMS
ADMIN_EMAIL	= admin@umsapp.com


#local database credentials
[localdb]
DB_HOSTNAME	= localhost
DB_USERNAME	= root
DB_PASSWORD	= ""
DB_PORT		= 3306
DB_NAME		= ecom


#production database credentials
[proddb]
PRD_DB_HOSTNAME	= localhost
PRD_DB_USERNAME	= root
PRD_DB_PASSWORD	= ""
PRD_DB_PORT	= 3306
PRD_DB_NAME	= ecom

global_functions.php

function getConnection() {
	
	$db = parse_ini_file('config/myapp.ini', true)['localdb'];
	
	$conn = null;
	
	$servername	= $db['DB_HOSTNAME'];
	$dbname		= $db['DB_NAME'];
	$username 	= $db['DB_USERNAME'];
	$password	= $db['DB_PASSWORD'];
	
	try {
	  $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
	  $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);	
	} catch(PDOException $e) {
	  echo "Error: " . $e->getMessage();
	}
	
	return $conn;
}

Ref: https://www.w3schools.com/php/func_filesystem_parse_ini_file.asp

Composer

A Dependency Manager for PHP

Composer is an application-level package manager for the PHP programming language that provides a standard format for managing dependencies of PHP software and required libraries. It was developed by Nils Adermann and Jordi Boggiano in 2012, who continue to manage the project.


To install composer in windows download and install executable file
https://getcomposer.org/download/

To install in ubuntu

apt install composer

To install latest version of composer on ubuntu

cd ~
curl -sS https://getcomposer.org/installer -o composer-setup.php

sudo php composer-setup.php --install-dir=/usr/bin --filename=composer

OR

sudo php composer-setup.php --install-dir=/usr/local/bin --filename=composer

composer.json
Keep this file in the project’s root directory
NOTE: This file is mandatory to in root directory to use composer as composer look for this file when you run dump-autoload

{
	"autoload" : {
		"files" : ["lib/global_functions.php"],
	}
}

lib/global_functions.php

function getMessage() {
	
	echo "Hello World" . PHP_EOL;

}

Create autoload file by running any one following command

composer dump-autoload
composer dump-autoload -o

index.php

<?php
require("vendor/autoload.php");
echo "=====================\n";
getMessage();

How to autoload classes using composer

app/admin/Account.php

<?php
namespace App\Admin;

class Account {
	//this is magic method as it will invoked automatically 
        //when you create instance of account
	public function __construct() {
		
		echo "I am from Admin Account" . PHP_EOL;
	}
}

app/user/Account.php

<?php
namespace App\User;

class Account {
	//this is magic method as it will invoked automatically 
	//when you create instance of account
	public function __construct() {
		echo "I am from User Account" . PHP_EOL;
	}	
}

modify composer.json

{
	"autoload" : {
		"files" : ["lib/global_functions.php"],
		"classmap" : ["app"]
	}
}

Once you modify composer.json file run dump-autoload command again to add classmapping in autoload file

composer update

OR

composer dump-autoload -o

modify index.php

<?php

require("vendor/autoload.php");

echo "=====================\n";

getMessage();

echo "=====================\n";

new App\User\Account();

echo "=====================\n";

new App\Admin\Account();

echo "=====================\n";
directory structure

Ref Code: https://gitlab.com/codeinsightacademy/composer-demo.git

PHP User Management System

A user or admin facing problem managing data on excel sheet.
He/She need a system to perform at least following operations

  1. Add Record
  2. Modify Record
  3. Delete Record
  4. Show Listing and Search Data to get specific Information.

User need a system which should be accessible from internet so that he can work from any machine (laptop/desktop/mobile).

You need to develop a web application with best of your knowledge

Roles: Admin

With correct credentials admin should be able to login and see the dashboard.

if credentials are wrong he will stay on login page and show a message – wrong credentials.

On successful login admin can see users list perform all CRUDL operations.

NOTE: you need to use vim editor to edit files

Following are the wireframes for reference.

login.php

dashboard.php

add_user.php

edit_user.php

delete confirm box

Technologies to be used

  • composer for package management and autoload
  • ini for configuration
  • git and gitlab for version control
  • HTML5 CSS3 Bootstrap 5 for UI/UX
  • jquery 3.6 or javascript for validation and AJAX
  • php 7.4 or 8 as backend programming language
  • mysql 8 database
  • PDO for database operations
  • PHPUnit for unit testing
  • python and php for automation script (Use cron jobs to automatically run script)
  • nginx web server
  • use infinityfree / webserver / cloudserver for website hosting
  • Jenkins and git-ftp for CI/CD

MVP / Deliverable

  1. P0
    1. Users Listing
    2. Delete User Record
    3. Add User Record with Profile Picture
      (User status should be enum in database table: enable, disable, blocked, active, inactive)
    4. Update User Record
    5. Session Management Login / Logout
  2. P1
    1. View User Details in Modal Window
    2. Pagination
    3. Sorting
    4. Searching
    5. Filtering
  3. P2
    1. Frontend – Backend Validation
    2. Export CSV Users
    3. Bulk Upload CSV
    4. Activity Log
    5. Export Activity Log
  4. P3
    1. Login with OTP i.e. 2FA (Use Redis to store OTP)
    2. Login Logout for user account
    3. Inactive User status if not logged in for 3 consecutive days
    4. Change Admin and User Password from their respective account
    5. Secret Questions and Forgot Password / Recover Password using secret questions or through the email link
  5. P4
    1. REST API (Web Services) for User CRUDL Operations
    2. Protect REST API using Basic Authentication or JWT token
    3. Login with google API or Facebook API
    4. PHPUnit test for all functionalities
    5. Licensing or limit user registration
  6. P5
    1. Dashboard showing following summary (Use highcharts)
      1. Total User
      2. Active Users
      3. License Count / Usage Count
      4. Online Users
      5. Weekly Registration Stats

Schema

Ref SQL Queries

SELECT * FROM users ORDER BY id DESC;

SELECT * FROM users WHERE id = 3;

DELETE FROM users WHERE id = 3;

INSERT INTO users (id, name, age, city, added_at, updated_at) VALUES (NULL, 'sonam gupta', 18, 'gorakhpur', NOW(), NOW());

UPDATE users SET name = 'Sonam Gupta', age = 20, city = 'Gorakhpur', updated_at = NOW() WHERE id = 5;

Reference

PHP MySQL CRUD App

Php CRUD Application – How to Create Website Using Php – YouTube

Linux Commands

SQL Cheat Sheet

HTML and CSS

Php Fundamentals

Php Basics Tutorial

Php Advanced Tutorial

Javascript Tutorial in Hindi

Javascript Tutorial in English