Call class method from variable – PHP

Sometimes you have to call the class method from the PHP variable. Let’s say you have a class with few functions with arguments.

<?php

class User
{
	public function list()
	{
		echo "Users list";
	}
	
	public function fetch($id)
	{
		echo "User fetch: " . $id;
	}
	
	public function update($id, $name)
	{
		echo "User update: " . $id . ", " . $name;
	}
}

Then you can create the class object from a variable like the following:

<?php

class User
{
	public function list()
	{
		echo "Users list";
	}
	
	public function fetch($id)
	{
		echo "User fetch: " . $id;
	}
	
	public function update($id, $name)
	{
		echo "User update: " . $id . ", " . $name;
	}
}

$class_name = "User";
$class_obj = new $class_name();

Now to call the method from that object, you can do:

<?php

class User
{
	public function list()
	{
		echo "Users list";
	}
	
	public function fetch($id)
	{
		echo "User fetch: " . $id;
	}
	
	public function update($id, $name)
	{
		echo "User update: " . $id . ", " . $name;
	}
}

$class_name = "User";
$class_obj = new $class_name();

$action_name = "list";
$class_obj->{$action_name}(); // echo "Users list"

You can also pass parameters to the method as well.

<?php

class User
{
	public function list()
	{
		echo "Users list";
	}
	
	public function fetch($id)
	{
		echo "User fetch: " . $id;
	}
	
	public function update($id, $name)
	{
		echo "User update: " . $id . ", " . $name;
	}
}

$class_name = "User";
$class_obj = new $class_name();

$action_name = "fetch";
$class_obj->{$action_name}(3); // echo "User fetch 3"

You can call multiple parameters as well.

<?php

class User
{
	public function list()
	{
		echo "Users list";
	}
	
	public function fetch($id)
	{
		echo "User fetch: " . $id;
	}
	
	public function update($id, $name)
	{
		echo "User update: " . $id . ", " . $name;
	}
}

$class_name = "User";
$class_obj = new $class_name();

$action_name = "update";
$class_obj->{$action_name}(5, "Adnan"); // echo "User update 5, Adnan"

Full code:

<?php

class User
{
	public function list()
	{
		echo "Users list";
	}
	
	public function fetch($id)
	{
		echo "User fetch: " . $id;
	}

	public function update($id, $name)
	{
		echo "User update: " . $id . ", " . $name;
	}
}

$class_name = "User";
$class_obj = new $class_name();

$action_name = "list";
$class_obj->{$action_name}(); // echo "Users list"

echo "<br />";

$action_name = "fetch";
$class_obj->{$action_name}(3); // echo "User fetch 3"

echo "<br />";

$action_name = "update";
$class_obj->{$action_name}(5, "Adnan"); // echo "User update 5, Adnan"

I have used this technique to create a lightweight PHP framework. Check out our other tutorials on PHP.

Custom routes – Htaccess tutorial

In this htaccess tutorial, you will learn how to create custom routes. You will also learn how you can prevent file listing using htaccess.

Video tutorial:

You need to create a file named “.htaccess” (note the dot at the start) at the root of your project. To prevent directory listing, write the following line in the “.htaccess” file.

Options -Indexes

Before using any routing rules and conditions, we must first activate them. Write the following line to activate the rewrite rules.

Options -Indexes
RewriteEngine On

Then we need to make sure the requests do not match any directory, file name, or symbolic link.

The following line checks if the requested file name is not a directory.

Options -Indexes
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d

The following line checks if the requested file name is not a file.

Options -Indexes
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f

The following line checks if the requested file name is not a symbolic link.

Options -Indexes
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l

Example 1:

Now, let’s say you want to redirect all the requests from the “users/list” route to the “users-list.php” file. You can do that by adding the following line in your htaccess file.

Options -Indexes
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^users/list$ users-list.php [L]

^ means the start of the string.

$ means the end of the string.

[L] means to stop looking for more RewriteRule if this condition matches.

Example 2:

Now let’s say you want to redirect all requests from the “users/fetch/1” route to the “user-by-id.php” file. Here, the last “1” is the parameter you want to send. Now to redirect the request to the file, you need to add the following rule:

Options -Indexes
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^users/list$ users-list.php [L]
RewriteRule ^users/fetch/([0-9]+)$ user-by-id.php?id=$1 [QSA,L]

([0-9]+) will match for any integer number.

?id=$1 means that it will send the parameter named “id“, with the value matched from the previous regular expression, to the file “user-by-id.php“.

QSA (Query String Append) will make sure to append the existing query string (if any) while preserving the additional parameters (id=1 in this case) to the URL.

Then in the “user-by-id.php” file, you can get the ID using the following code:

<?php

echo $_GET["id"];

?>

Example 3:

For instance, if you want to redirect the URL “users/fetch/adnan” (‘adnan’ is the argument) to the file “user-by-name.php“, you can do that by adding the following rewrite rule.

Options -Indexes
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^users/list$ users-list.php [L]
RewriteRule ^users/fetch/([0-9]+)$ user-by-id.php?id=$1 [QSA,L]
RewriteRule ^users/fetch/([a-zA-Z\s-]+)$ user-by-name.php?name=$1 [QSA,NC,L]

([a-zA-Z\s-]+) This regular expression will match all alphabets, including multiple words, letters, spaces, and hyphens.

NC This flag will make the match case insensitive.

Then in the “user-by-name.php” file, you can get the name using the following code:

<?php

echo $_GET["name"];

?>

Following is the complete code of the “.htaccess” file.

Options -Indexes
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^users/list$ users-list.php [L]
RewriteRule ^users/fetch/([0-9]+)$ user-by-id.php?id=$1 [QSA,L]
RewriteRule ^users/fetch/([a-zA-Z\s-]+)$ user-by-name.php?name=$1 [QSA,NC,L]

Download:

custom-routes-htaccess.zip

If you are running on HTTP, you can make your web server redirect the HTTP requests to HTTPS following this tutorial.

I also created a simple and lightweight PHP MVC framework using this htaccess rewrite condition. You can check it out here.

This concludes our htaccess tutorial on creating custom routes. If you face any issues with this, kindly let me know.

TrustPilot clone – PHP, MySQL, Laravel

A clone of TrustPilot website is created in PHP and MySQL using Laravel framework version 11. For frontend rendering, I am using Vue JS 3 and on admin side I am using React JS.

Files included:

  • .php
  • .css
  • .js

Features:

  1. User can post reviews about a company.
  2. Can flag a review.
  3. Can share reviews on social media.
  4. Company owners can claim a company by verifying their email address.
  5. Automatically takes screenshot of a company home page.
  6. Admin can add companies from admin panel.
  7. Admin can view all reviews, flags and claims.

Demo:

Show loader on AJAX – VueJS

Today, you will learn, how you can show a loader in VueJS when an AJAX is called. We will be using Axios library for calling AJAX request.

If you do not want to use Axios library, you can use the default XMLHttpRequest object of Javascript. Learn how to do it from here.

Video tutorial:

Let’s say we have the following code that:

  1. Includes VueJS and Axios library.
  2. Create a div for Vue app.
  3. Mount Vue app onto the div.
  4. On mounted, calls an AJAX request.
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

<div id="app"></div>

And following javascript code will mount the Vue app.

Vue.createApp({
	async mounted() {
		const response = await axios.post(
			"https://api.github.com/users/adnanafzal565"
		)
		
		console.log(response)
	}
}).mount("#app")

Now, I will create a loading text that will be displayed only if the loading variable is true.

<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

<div id="app">
	<p v-if="loading">Loading...</p>
</div>

Then I will create that variable in my Vue app and initialize it as false.

Vue.createApp({

	data() {
		return {
			loading: false
		}
	},

	async mounted() {
		const response = await axios.post(
			"https://api.github.com/users/adnanafzal565"
		)
		
		console.log(response)
	}
}).mount("#app")

Lastly, we are going to set this variable to true before calling the AJAX and false after the AJAX is finished.

Vue.createApp({

	data() {
		return {
			loading: false
		}
	},

	async mounted() {
		this.loading = true
		
		const response = await axios.post(
			"https://api.github.com/users/adnanafzal565"
		)
		
		this.loading = false
		
		console.log(response)
	}
}).mount("#app")

So that’s it. That’s how you can show a loader while AJAX is being called in VueJS.

Save and display images in Binary – NodeJS

In this tutorial, you will learn, how you can save and display images in Binary in NodeJS and MongoDB.

We will also create an API that will return a binary image as a response.

Saving images in the database has many advantages over saving images in file storage.

  1. First, if you are deploying in Heroku, they do not provide persistent storage for their free tier. This means that the files uploaded on Heroku will automatically be removed after 30 minutes of inactivity.
  2. Second, migrating from one deployment platform to another is easy. Since you do not have to move all the uploaded files too. You can use mongodb.com for your MongoDB database and use this on all platforms.
  3. Third, we will be saving images in Binary format so it will take less space than saving in Base64.

Video tutorial:

The following route will save the user-uploaded image as Binary in MongoDB using NodeJS.

// npm install fs
// import file system module
const fs = require("fs")

app.post("/upload", async function (request, result) {
    // get user-uploaded file
    const image = request.files.image
  
    // reading file data
    const fileData = await fs.readFileSync(image.path)
    
    // converting to binary
    const binary = Buffer.from(fileData)
    
    // saving in database
    await db.collection("images").insertOne({
        path: binary
    })
    
    // sending response back to client
    result.send("Done")
})

Check out this tutorial if you want to know how to connect with MongoDB.

Now that the image has been saved, we will create a GET route that will return the image as a base64 string.

// set EJS as templating engine
app.set("view engine", "ejs")

app.get("/", async function (request, result) {
    // get image from collection
    const image = await db.collection("images")
        .findOne({})
        
    // variable to get base64 string
    let imageString = ""
    
    // check if document exists
    if (image != null) {
        // image.path will return binary
        // buffer() function is called on binary object
        imageString = "data:image/png;base64," + image.path.buffer.toString("base64")
    }
    
    // sending data to file "views/index.ejs"
    result.render("index", {
        image: imageString
    })
})

After that, we need to create a folder named “views” and inside it a file named “index.ejs” and write the following code in it:

<img src="<%= image %>" style="width: 100%;" />

That’s how you can save and display images in Binary in NodeJS and MongoDB.

Remove array element inside for loop – Javascript

In this article, you will learn, how to remove an array element in a for loop using Javascript. We will be looping in reverse.

Video tutorial:

You can use the following code:

// sample array
const categories = [
  {
    category: "Laptop",
    products: ["Macbook pro", "Acer aspire 5", "Dell XPS", "Lenovo Ideapad"]
  },
  
  {
    category: "Mobile",
    products: ["Samsung Galaxy S23", "Apple iPhone 15"]
  }
]

// looping through all array elements in reverse
for (let a = categories.length - 1; a >= 0; a--) {
  // condition criteria
  if (categories[a].products.length > 3) {
    // remove array element
    categories.splice(a, 1)
  }
}

This will delete all categories having more than 3 products.

MongoDB GridFS

In this tutorial, you will learn, how you can upload, retrieve, and delete files using MongoDB GridFS.

Video tutorial:

Upload the file to MongoDB GridFS

First, in your Node JS file, you need to create an instance of your GridFS bucket. You can create as many buckets as you want.

// include MongoDB
const mongodb = require("mongodb")

// get MongoDB client
const mongoClient = mongogb.MongoClient

// connect with MongoDB server
const client = await mongoClient.connect("mongodb://localhost:27017")

const db = client.db("mongodb_gridfs")

// create GridFS bucket instance
const bucket = new mongodb.GridFSBucket(db)
  1. First, it includes the MongoDB module.
  2. Then it gets a Mongo client object that helps in connecting with the database.
  3. Then we connect to the server.
  4. After that, we set the database.
  5. And finally, we are creating an instance of a bucket.

You can also give your bucket a name to identify.

// create GridFS bucket instance named "myBucketName"
const bucket = new mongodb.GridFSBucket(db, {
  bucketName: "myBucketName"
})

Following POST route will save the file.

// npm install fs
const fs = require("fs")

// npm install ejs
app.set("view engine", "ejs")

// npm install express-formidable
const expressFormidable = require("express-formidable")
app.use(expressFormidable())

app.post("/upload", function (request, result) {
  // get input name="file" from client side
  const file = request.files.file
  
  // set file path in MongoDB GriDFS
  // this will be saved as "filename" in "fs.files" collection
  const filePath = (new Date().getTime()) + "-" + file.name
  
  // read user uploaded file stream
  fs.createReadStream(file.path)
  
    // add GridFS bucket stream to the pipe
    // it will keep reading and saving file
    .pipe(
      bucket.openUploadStream(filePath, {
        // maximum size for each chunk (in bytes)
        chunkSizeBytes: 1048576, // 1048576 = 1 MB
        // metadata of the file
        metadata: {
          name: file.name, // file name
          size: file.size, // file size (in bytes)
          type: file.type // type of file
        }
      })
    )
    // this callback will be called when the file is done saving
    .on("finish", function () {
      result.send("File saved.")
    })
})

Now if you check in your “mongodb_gridfs” database, you will see 2 new collections.

  1. fs.files
    • This will save all uploaded files.
  2. fs.chunks
    • This will save all chunks of each file with that file ID.

Fetch all files from MongoDB GridFS

The following GET route will fetch all files uploaded to MongoDB GridFS.

app.get("/", async function (request, result) {
  const files = await bucket.find({
    // filename: "name of file" // 
  })
    .sort({
      uploadDate: -1
    })
    .toArray()
  result.render("index", {
    files: files
  })
})

Now you need to create a folder named “views” and inside that folder create a file named “index.ejs”.

Then you can loop through all files and display them in the image tag.

<% if (files) { %>
  <% files.forEach(function (file) { %>
    <p><%= file.filename %></p>
    <img src="image/<%= file.filename %>" style="width: 200px;" />
  <% }) %>
<% } %>

Right now, you will see a broken image. Now we need to create an API that will return the image as a response.

Return image as API response

app.get("/image/:filename", async function (request, result) {
  // get file name from URL
  const filename = request.params.filename
  
  // get file from GridFS bucket
  const files = await bucket.find({
    filename: filename
  })
  .toArray()
  
  // return error if file not found
  if (!files || files.length == 0) {
    return result.status(404).json({
      error: "File does not exists."
    })
  }
  
  // it will fetch the file from bucket and add it to pipe
  // result response is added in the pipe so it will keep
  // returning data to the client
  bucket.openDownloadStreamByName(filename)
    .pipe(result)
})

Now you will be able to view the image.

Delete file from MongoDB GridFS

First, you need to create a button after each file.

<% if (files) { %>
  <% files.forEach(function (file) { %>
    <p><%= file.filename %></p>
    <img src="image/<%= file.filename %>" style="width: 200px;" />
    
    <form action="/files/del" method="POST">
      <input type="hidden" name="_id" value="<%= file._id %>" />
      <button type="submit" class="btn btn-danger">Delete</button>
    </form>
  <% }) %>
<% } %>

Then you need to create an API in your Node JS file.

// 
const ObjectId = mongodb.ObjectId

app.post("/files/del", async function (request, result) {
  // get ID from data
  const _id = request.fields._id
  
  // delete file from bucket
  await bucket.delete(ObjectId(_id))
  
  // return response
  result.send("File has been deleted.")
})

This will delete the file and all its chunks from the database. So that’s all for now if you face any problem in following this, kindly do let me know.

You can learn more about the grid file system from Mongo DB’s official website.

Manage website using Git – Shared, VPS, Dedicated

In this article, you will learn how you can manage your website, hosted on Shared, VPS, or dedicated server, using Git version control.

Video tutorial:

This tutorial works for all Shared, VPS, and dedicated hosting servers.

I have created a simple “Hello world” PHP file.

<?php

echo "Hello world";

I have created a sub-domain and Git repo on my shared hosting. You can check it from the video above.

Once a Git repo is created, it will give you an SSH path. I am going to open CMD in my folder and initialize Git in it.

cd "my-project-folder"
git init
git remote add origin ssh://adnantech@adnan-tech.com/home2/adnantech/git.adnan-tech.com
git status
git add .
git commit -m "Initial commit."
git push origin master

It will ask for your username and password. You can enter the credentials you use to log in to your hosting server.

If you receive the following error:

fatal: bad config value for ‘receive.denycurrentbranch’ in config

You can fix it by first accessing SSH from your terminal: (make sure to replace it with your username and IP address)

ssh -p 2222 adnantech@162.241.216.155

It will again ask for your password. Once the password is entered, you will be entered into the SSH terminal.

Once inside the SSH terminal, enter the following command:

which git-receive-pack

It will return the path of your Git receive pack. Copy it. Then push the code using the following command:

git push origin master -u --exec=your_git_receive_pack

Replace “your_git_receive_pack” with your Git receive-pack returned from the previous command.

I am going to make some changes in my code.

<?php

echo "Hello world of programming...";

Then I am going to push again.

git add -A
git commit -m "Changes made."
git push origin master -u --exec=your_git_receive_pack

You will now see updated code pushed to your website.

So that’s it. That’s how you can manage your shared, VPS, or dedicated server’s website code using Git.

You can watch the video if you are having problems following the article.

If you still face any issues with this, you can let me know.

More: Learn how to deploy Node JS app on VPS or dedicated hosting.

API to return image in Node JS

In this article, we will show you, how you can return an image from the response of an API in Node JS.

Video tutorial:

First, I will create an image tag and set the “src” attribute as the path of the API. I also send “adnan” as an argument so the server will know which image to fetch.

<img src="/showImage/adnan" />

Then I am going to create a GET API in Node JS.

const fs = require("fs")

app.get("/showImage/:name", async function (request, result) {
  const name = request.params.name
  const image = await db.collection("images")
    .findOne({
      name: name
    })
  if (image == null) {
    let defaultImage = await fs.readFileSync("public/default.jpg")
    defaultImage = Buffer.from(defaultImage, "base64")
    
    result.writeHead(200, {
      "Content-Type": "image/jpg",
      "Content-Length": defaultImage.length
    })
    result.end(defaultImage)
    return
  }
  
  const imageContent = await fs.readFileSync(image.path)
  
  result.writeHead(200, {
    "Content-Type": "image/jpg",
    "Content-Length": imageContent.length
  })
  result.end(imageContent)
  return
})

If you run the code now, you will be able to see the image.