Callback function in React JS

In this article, we will teach you how you can use a callback function to be called from child parent that will invoke a function in parent component in React JS.

Let’s say you have:

  • A parent component that has an array.
  • You are looping through an array and displaying the data using child component.
  • You want to call a function from child component that will invoke a function in parent component.
<html>
    <head>
        <script src="js/babel.min.js"></script>
        <script src="js/react.development.js"></script>
        <script src="js/react-dom.development.js"></script>

        <script type="text/babel" src="js/SingleData.js"></script>
    </head>

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

        <script type="text/babel">
            function App() {

                const [data, setData] = React.useState([{
                    id: 1,
                    name: "Adnan",
                    age: 31
                }, {
                    id: 2,
                    name: "Afzal",
                    age: 65
                }, {
                    id: 3,
                    name: "Ali",
                    age: 43
                }]);

                return (
                    <>
                        { data.map(function (d, index) {
                            return (
                                <SingleData key={ `data-${ d.id }` }
                                    d={ d } />
                            );
                        }) }
                    </>
                );
            }

            ReactDOM.createRoot(
                document.getElementById("app")
            ).render(<App />);
        </script>
    </body>
</html>

Here, we have a React parent component that has an array of data. Each array element has an ID, name and age. You might be receiving this data from API. In each loop iteration, it is rendering a child component.

  • key: This is used by React JS to uniquely identify an element.
  • d: This is the property value parent component is sending to the child component.

What are props in React JS ?

props (properties): Props are used in React JS to pass the data from parent component to child component. They are read-only so child component cannot modify the value of “d”.

Our child component will look like this:

// js/SingleData.js

function SingleData({ d }) {
    return (
        <div>
            <p>
                { d.id } - { d.name } { d.age }
            </p>
        </div>
    );
}

Callback function

Now, let’s assume you want to have a delete function in child component that, when called, will call a function in parent component. So that the parent component that perform an action on that child. In this case, we will remove that array element from “data” array in parent component.

So first, we will create a delete button in child parent. Once that button is clicked, we will call a function we will receive in props from parent component.

// js/SingleData.js

function SingleData({ d, onDelete }) {
    return (
        <div>
            <p>
                { d.id } - { d.name } { d.age }
            </p>

            <button type="button"
                onClick={ function () {
                    onDelete(d.id);
                } }>Delete</button>
        </div>
    );
}

Now, in our parent component, we need to pass this function as an argument to the child component.

<SingleData key={ `data-${ d.id }` }
    d={ d }
    onDelete={ onDelete } />

Finally, we will create that function in parent component that will search the array element using ID and remove it from array. At the end, we will update the React state variable as well.

function onDelete(id) {
    const tempArr = [ ...data ];
    for (let a = 0; a < tempArr.length; a++) {
        if (tempArr[a].id == id) {
            tempArr.splice(a, 1);
            break;
        }
    }

    setData(tempArr);
}

Here is the complete code of this tutorial.

Parent component

<html>
    <head>
        <script src="js/babel.min.js"></script>
        <script src="js/react.development.js"></script>
        <script src="js/react-dom.development.js"></script>

        <script type="text/babel" src="js/SingleData.js"></script>
    </head>

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

        <script type="text/babel">
            function App() {

                const [data, setData] = React.useState([{
                    id: 1,
                    name: "Adnan",
                    age: 31
                }, {
                    id: 2,
                    name: "Afzal",
                    age: 65
                }, {
                    id: 3,
                    name: "Ali",
                    age: 43
                }]);

                function onDelete(id) {
                    const tempArr = [ ...data ];
                    for (let a = 0; a < tempArr.length; a++) {
                        if (tempArr[a].id == id) {
                            tempArr.splice(a, 1);
                            break;
                        }
                    }

                    setData(tempArr);
                }

                return (
                    <>
                        { data.map(function (d, index) {
                            return (
                                <SingleData key={ `data-${ d.id }` }
                                    d={ d }
                                    onDelete={ onDelete } />
                            );
                        }) }
                    </>
                );
            }

            ReactDOM.createRoot(
                document.getElementById("app")
            ).render(<App />);
        </script>
    </body>
</html>

Child component

function SingleData({ d, onDelete }) {
    return (
        <div>
            <p>
                { d.id } - { d.name } { d.age }
            </p>

            <button type="button"
                onClick={ function () {
                    onDelete(d.id);
                } }>Delete</button>
        </div>
    );
}

We used this method in one of our project “Multi-purpose platform in Node JS and Mongo DB“. You can check this out if you want to get a practically view of it.

That is how you can use a callback function in React JS that will invoke a function from child component to parent component.

Free tool to write API documentation – PHP, MySQL

I was looking for a tool that allows me to write API documentation so I can provide it to the frontend developers and also for myself. I checked many but didn’t find any that fits to all of my requirements. So I decided to create one of my own. Creating my own tool gives me flexibility to modify it as much as I want.

I also wanted it to share it with other developers who might be having problem in finding the tool to write documentation for their API. So I uploaded it on Github and it is available for anyone for free.

How to write API documentation

A tool is created in PHP and MySQL that allows developers to write API documentation, and this tool is available for free. You can create multiple sections to group the APIs based on modules. For example, user authentication, user posts, comments, replies can be separate sections.

To write each API, you need to tell:

  • The section where it goes.
  • The name of the endpoint. It can be the URL of API.
  • The method, it can be either GET or POST. But since you will have the code, you can add more methods as per your needs.
  • Add a little description about the API, for example what this API does.
  • Headers:
    • You need to tell the key of header, whether it is required or optional. And a little description about the header, for example, it’s possible values.
  • Parameters:
    • Parameters are usually send in the URL. You can define them along with their key, and value and whether they are optional or not.
  • Arguments:
    • For defining the arguments, you need to specify it’s type too. Whether it can be an integer, a string, boolean value or a file object.
  • Example request body. You can write the CURL code inside it to give an example.
  • Status codes and their responses.

I wrote a complete documentation of a project using this tool. You can check that from here.

Download

Include React JS component dynamically

In order to include a React JS component dynamically, we need to use the Javascript’s built-in fetch API. Let’s say you have a simple component that renders an <h1> tag:

// js/MyComponent.js

// create a simple component
function MyComponent() {
    return (
        <h1>My Component</h1>
    );
}

// render component
ReactDOM.createRoot(
    document.getElementById("my-component")
).render(<MyComponent />);

And in your index.html, you have your main React JS app.

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

<script type="text/babel">
    function App() {
        return (
            <>
                <div id="my-component"></div>
            </>
        );
    }

    ReactDOM.createRoot(
        document.getElementById("app")
    ).render(<App />);
</script>

Now you want to render your React JS component “MyComponent” dynamically in div having id=”my-component”. First, you need to use the fetch API to get the content of MyComponent.js file.

<script>

    // fetch component file content
    fetch("js/MyComponent.js")
        .then(function (response) {

            console.log(response.text());

        });

</script>
  • fetch: Fetch is a built-in modern browser API that allows you to execute HTTP requests.
  • response.text(): It will return not an actual string, but a promise. We need to resolve it by again chaining it with then() function.

Now we need to resolve the promise to get the actual string from response.

response.text().then(function (text) {
    console.log(text);
});

If you check your browser console now, you will see the exact code you have in your React JS component file. But this code is in JSX format, we need to compile it to native Javascript code. We can do that using Babel library:

// compile babel code to native javascript
const transpiledCode = Babel.transform(text, {
    presets: ["env", "react"]
}).code;

console.log(transpiledCode);

If you see the browser console now, you will see the native Javascript code.

  • Babel.transform: This function is used to transform the code from one format to another. It takes the code that needs to be transformed as 1st argument and an object for other options as 2nd argument.
  • presets: It will be an array that tells the Babel how to transform this code.
  • env: This ensures to convert the code such that it supports the older environments of Javascript like ES5.
  • react: This will convert the JSX or React code into plain Javascript code.
  • .code: This property will return the transformed code as string.
Convert JSX or React to native JS
Convert JSX to JS

Now we just need to execute this to render our React JS component dynamically. So we will simply use the eval() function that takes Javascript code as input string and execute it.

eval(transpiledCode);

Here is the complete code to include the React JS component dynamically in your project.

js/MyComponent.js

// create a simple component
function MyComponent() {
    return (
        <h1>My Component</h1>
    );
}

// render component
ReactDOM.createRoot(
    document.getElementById("my-component")
).render(<MyComponent />);

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <title>Include React JS component dynamically</title>

        <script src="js/react.development.js"></script>
        <script src="js/react-dom.development.js"></script>
        <script src="js/babel.min.js"></script>
    </head>

    <body>

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

        <script type="text/babel">
            function App() {
                return (
                    <>

                        <div id="my-component"></div>

                    </>
                );
            }

            ReactDOM.createRoot(
                document.getElementById("app")
            ).render(<App />);
        </script>

        <script>
            
            // fetch component file content
            fetch("js/MyComponent.js")
                .then(function (response) {

                    // text content of file
                    // it is a promise, so we will execute it
                    response.text().then(function (text) {

                        console.log(text);
                        
                        // compile babel code to native javascript
                        const transpiledCode = Babel.transform(text, {
                            presets: ["env", "react"]
                        }).code;

                        console.log(transpiledCode);

                        // execute the code as javascript
                        eval(transpiledCode);

                    });

                });

        </script>

    </body>
</html>

Download

Freelance Status – A tool for freelancers

Freelance Status is a tool for freelancers to update clients about their work progress. You can download it for free.

Technologies used

  • Laravel
    • I have used Laravel framework for building this project basic structure and APIs. It is also a very good framework with many built-in security features. It can also be deployed on shared hosting as well.
  • React JS
    • All the pages on client and admin side are rendered in React JS. This is not a Single Page Application (SPA) but the HTML is rendered by React JS.
  • Bootstrap
    • Bootstrap is used for building structure and layout of website. It is also very helpful for responsive design.

Features

In “Freelance Status”, there are 2 panels. One for freelancer and one for client. Freelancer portal is actually the admin panel because he can add his clients, projects and tasks. He can update the status of his tasks etc. But client can only see the progress of their tasks from user side.

Admin panel (freelancer)

You (as a freelancer) holds the admin panel. You can:

  • Add, edit or delete clients. While adding clients, you can enter their name, email, phone (if have) and password. You can let them know their password via message or inbox so they can access the client side.
  • You can add projects for each client. While adding projects, you can enter the name of the project. Then you can select the client of that project via dropdown. In dropdown, you will see a list of all clients added from previous step.
  • Similarly, you can add tasks of each project. For adding tasks, you have to provide many values.
    • Task title and its description.
    • The price of that task.
    • The status (todo, progress or done).
    • The payment status. It can be either (paid, not paid, not finalized). Payment “not finalized” means that the amount is not yet decided between client and freelancer. But you are saving the task so it can be discussed later.
    • Select the client.
    • Select the project this task belongs to.

Client side

  • Clients will first have to login using the email and password provided by freelancer.
  • After login, they will see all their projects on home page.
  • With each project, they will see a link “View tasks”. On clicking that, they will be redirected to a new page.
  • On this page, they can see a list of all tasks in that project. They can also see the price, status and payment status of each task.
  • With each task, a button saying “Detail” is displayed. When clicked, will display a modal containing the details of the task.

Installation

Following steps helps you install this project on your localhost. If you want to learn how to deploy this on your live server, check our this guide.

Step 1

First you need to create a database named “freelance_status”, or any other name of your choice, in your phpMyAdmin.

Step 2

Then you need to set your database credentials in “config/database.php” file. Here you can set your database name, username and its password.

Note: If you are working on live server, make sure you have given that user all permissions to your database.

Step 3

Open command prompt or terminal at the root of this project and run the following commands:

COMPOSER_MEMORY_LIMIT=-1 composer update

This will install all the required libraries for this project. Make sure you have composer installed in your system. COMPOSER_MEMORY_LIMIT=-1 will prevent you from timeout exception.

Note: For live server, you can talk with your hosting provider customer support to install composer.

Step 4

Set storage link in your public folder by running the following command:

php artisan storage:link

This will create a shortcut link of storage/app/public folder into your public folder. It allows you to access your files stored in storage from public directory.

Step 5

Next step is to generate an application key for your project.

php artisan key:generate

This will generate a random string of 32 characters. The key will automatically be saved in APP_KEY variable of your .env file.

Step 6

If you have set your database credentials, you can run the following command.

php artisan migrate

It will create all the tables required for your project.

Step 7

After running the migration, we need to run the seeder.

name="Admin" email="admin@gmail.com" password="admin" php artisan db:seed –class=DatabaseSeeder

A super admin will be added in “users” table. You can set your own name, email and password here.

Step 8

Finally you can run your project by running the following command.

php artisan serve

If you run the URL “http://127.0.0.1:8000” in your browser, you will see your project. If anything goes wrong, feel free to contact me.

“Freelance Status” allows you to add clients, their projects and tasks from admin panel. And clients can see them trough a user side. Clients do not have to keep asking you about update on the project. And you can focus more on work than on updating the client about progress.

FTP manager in PHP, MySQL, Laravel

I created an online free FTP manager in PHP that allows developers to work on their projects from anywhere. I created this tool in PHP and MySQL using Laravel framework. The frontend is designed in Bootstrap and React JS.

Let’s discuss each feature and I will also show you how I built this.

What you will learn:

  • Connect with FTP.
  • List files from FTP directory.
  • Fetch file content.
  • Edit FTP file.
  • Create a new file.
  • Create a new folder.
  • Upload files.
  • Download files.
  • Rename file.
  • Delete file.
  • Delete folder.

We created a PHP class named “FTP” in a file called “FTP.php”. All our functions will go in that class.

1. Connect with FTP

The first step is to connect with FTP server. Following code will create a function that will connect with your FTP server (we are not calling it yet).

class FTP
{
    private $conn_id = null;
    private $server = "";
    private $username = "";
    private $password = "";
    
    private function do_connect()
    {
        try
        {
            // Establishing connection
            $this->conn_id = ftp_connect($this->server);

            if (!$this->conn_id)
            {
                echo json_encode([
                    "status" => "error",
                    "message" => "Could not connect to " . $this->server
                ]);
                exit();
            }

            // Login with username and password
            $login_result = ftp_login($this->conn_id, $this->username, $this->password);

            if (!$login_result)
            {
                echo json_encode([
                    "status" => "error",
                    "message" => "Wrong password for '" . $this->username . "'."
                ]);
                exit();
            }

            // Enable passive mode for better compatibility
            ftp_pasv($this->conn_id, true);
        }
        catch (\Exception $exp)
        {
            echo json_encode([
                "status" => "error",
                "message" => "Could not connect to " . $this->server
            ]);
            exit();
        }
    }
}

Comments has been added with each line for explanation. Make sure to enter your correct FTP server address, FTP account’s username and its password. In the next step, we will call this function to connect with FTP server.

2. List files from FTP directory

The next step is to list all files from FTP directory. Create the following function in your FTP class.

public function fetch_files()
{
    $this->do_connect();
    $path = "/directory-name";

    // Get file listing
    $file_list = ftp_nlist($this->conn_id, $path);

    if ($file_list === false)
    {
        echo json_encode([
            "status" => "error",
            "message" => "Error retrieving file list."
        ]);
        exit();
    }

    $files = [];
    foreach ($file_list as $file)
    {
        $obj = [
            "file" => $file,
            "size" => ftp_size($this->conn_id, $file)
        ];

        if ($obj["file"] != "." && $obj["file"] != "..")
        {
            array_push($files, $obj);
        }
    }

    // Close the connection
    ftp_close($this->conn_id);

    echo json_encode([
        "status" => "success",
        "message" => "Data has been fetched.",
        "files" => $files
    ]);
    exit();
}
  • This function will first connect with the FTP server.
  • Then it will fetch all the files from $path variable.
    • If the directory does not exists or if it does not have read permission, then it will return an error.
  • All files from that directory will be put in an array along with the size of the file in bytes.
    • If it is a directory, then it’s size will be -1.
  • Finally, it returns the array with the response.

3. Fetch file content

Reading the content of FTP file is necessary because in order to edit the file, we need to first view the file. Following function will fetch the content of file and return it in response.

public function fetch_content()
{
    $this->do_connect();
    $file = "/directory-name/file-name.php";

    // Local path for downloading the file
    $local_file = tempnam(sys_get_temp_dir(), 'ftp_download');

    // Download the file from FTP server to local file
    if (!ftp_get($this->conn_id, $local_file, $file, FTP_BINARY))
    {
        echo json_encode([
            "status" => "error",
            "message" => "Failed to read '" . $file . "'"
        ]);
        exit();
    }

    // Read contents of the local file
    $file_content = file_get_contents($local_file);
    
    // Display or process the file content as needed
    if ($file_content === false)
    {
        echo json_encode([
            "status" => "error",
            "message" => "Failed to read file content."
        ]);
        exit();
    }

    // Clean up: Delete the temporary local file
    unlink($local_file);

    echo json_encode([
        "status" => "success",
        "message" => "Data has been fetched.",
        "content" => $file_content
    ]);
    exit();
}
  • It will first download the file in a temporary directory to your server.
  • If the file does not exists, then it will return an error.
  • It will return an error if it fails to read the FTP file.
    • Usually it is because if the $path variable is a directory or an image or document file.
  • After the file’s content is fetched, we will remove the temporary file from our server.

4. Edit FTP file

After the file’s content is successfully fetched, the next step is to update the file. You are working in FTP, editing the code is what you will be doing most of the time.

Updating the content of file requires 2 steps:

  1. Saving the file in temporary folder.
  2. Uploading the temporary file on FTP server.
public function update_content()
{
    $this->do_connect();

    $file = "/directory-name/file-name.php";
    $content = "console.log(\"Hello world\")";

    // Local path for downloading the file
    $local_file = tempnam(sys_get_temp_dir(), 'ftp_download');

    // Write the new content to a local temporary file
    file_put_contents($local_file, $content);

    if (!ftp_put($this->conn_id, $remote_file, $local_file, FTP_ASCII))
    {
        echo json_encode([
            "status" => "error",
            "message" => "There was a problem updating '" . $remote_file . "'"
        ]);
        exit();
    }

    unlink($local_file);

    // Close the FTP connection
    ftp_close($this->conn_id);

    echo json_encode([
        "status" => "success",
        "message" => "File has been updated."
    ]);
    exit();
}

5. Create a new file

Creating a new file in FTP in PHP is as simple as updating the file. We just need to set the content of file as empty string. So we will be uploading an empty file to FTP server.

public function create_file()
{
    $this->do_connect();
    
    $path = "/directory-name";
    $name = "file-name.php";

    // Local file content to be uploaded
    $file_content = "";

    // Local path for downloading the file
    $local_file = tempnam(sys_get_temp_dir(), 'ftp_download');

    // Write the content to a temporary local file
    file_put_contents($local_file, $file_content);

    // Remote file path where the file will be created
    $remote_file = $path . "/" . $name; // Replace with the desired remote file path

    // Upload the local file to the FTP server
    if (!ftp_put($this->conn_id, $remote_file, $local_file, FTP_ASCII))
    {
        echo json_encode([
            "status" => "error",
            "message" => "There was a problem while creating '" . $name . "'"
        ]);
        exit();
    }

    unlink($local_file);

    // Close the FTP connection
    ftp_close($this->conn_id);

    echo json_encode([
        "status" => "success",
        "message" => "Successfully created '" . $name . "'"
    ]);
    exit();
}
  • Create a temporary empty file on local directory.
  • Upload it to FTP.
  • Remove the file from local directory.

6. Create a new folder

Creating a folder is must easier than creating a file on FTP server.

public function create_folder()
{
    $this->do_connect();

    $path = "/directory-name";
    $name = "folder-name";

    $folder = $path . "/" . $name;

    if (!ftp_mkdir($this->conn_id, $folder))
    {
        echo json_encode([
            "status" => "error",
            "message" => "There was a problem while creating '" . $name . "'"
        ]);
        exit();
    }

    echo json_encode([
        "status" => "success",
        "message" => "Successfully created '" . $name . "'"
    ]);
    exit();
}

Note: It will return an error if the directory already exists.

7. Upload files

To upload the file from local computer to FTP server, you need to first save it in your local server. Then upload the file to FTP server. After it is successfully uploaded, you can remove the file from local server.

public function upload()
{
    $this->do_connect();

    $path = "/directory-name";
    $file_name = basename($_FILES["file"]["name"]);
    $target_file = "uploads/" . $file_name;

    if (!move_uploaded_file($_FILES["file"]["tmp_name"], $target_file))
    {
        echo json_encode([
            "status" => "error",
            "message" => "The file " . htmlspecialchars(basename( $_FILES["file"]["name"])) . " has been uploaded."
        ]);
        exit();
    }

    if (!ftp_put($this->conn_id, $file_name, $target_file, FTP_ASCII))
    {
        echo json_encode([
            "status" => "error",
            "message" => "There was a problem updating '" . $file_name . "'"
        ]);
        exit();
    }

    // Close the FTP connection
    ftp_close($this->conn_id);

    echo json_encode([
        "status" => "success",
        "message" => "File(s) has been uploaded."
    ]);
    exit();
}

If you are working in Laravel, your upload function should be like this:

public function upload()
{
    $this->do_connect();
    $path = "/directory-name";

    $files = request()->file("files");
    foreach ($files as $file)
    {
        $remote_file = $file->getClientOriginalName();

        $file_path = "ftp/" . $file->getClientOriginalName();
        $file->storeAs("/private", $file_path);

        if (!ftp_put($this->conn_id, $remote_file, storage_path("app/private/" . $file_path), FTP_ASCII))
        {
            return response()->json([
                "status" => "error",
                "message" => "There was a problem updating '" . $remote_file . "'"
            ]);
        }

        Storage::delete("private/" . $file_path);
    }

    // Close the FTP connection
    ftp_close($this->conn_id);

    return response()->json([
        "status" => "success",
        "message" => "File(s) has been uploaded."
    ]);
}

8. Download files

Downloading the file to local computer requires 2 steps.

  1. First is to download the file on local server from FTP server.
  2. Then download it to local computer from local server.

Download file from FTP to local server

Following code will be used to download the file on local server.

public function download()
{
    $this->do_connect();

    $path = "/directory-name";
    $file = "file-name.php";

    // Local path for downloading the file
    $local_file = tempnam(sys_get_temp_dir(), 'ftp_download');

    $remote_file = $path . "/" . $file;

    // Download the file from FTP server to local file
    if (!ftp_get($this->conn_id, $local_file, $remote_file, FTP_BINARY))
    {
        echo json_encode([
            "status" => "error",
            "message" => "Failed to download '" . $remote_file . "'"
        ]);
        exit();
    }

    // Create a unique download URL for the file
    $download_url = url('download.php?file=' . urlencode($local_file) . '&name=' . urlencode($file));

    // Close the FTP connection
    ftp_close($this->conn_id);

    echo json_encode([
        "status" => "success",
        "message" => "File has been downloaded.",
        "download_url" => $download_url
    ]);
    exit();
}

It will also return the “download_url” variable. That will be link to file from where you can download the file.

Download from server to local computer

Create a new file named “download.php” in your server and write the following code in it:

if (isset($_GET['file']) && isset($_GET['name']))
{
    $temp_file = $_GET['file'];
    $file_name = $_GET['name'];

    if (file_exists($temp_file))
    {
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="' . $file_name . '"');
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');
        header('Content-Length: ' . filesize($temp_file));

        // Read the file and output it to the browser
        readfile($temp_file);

        // Delete the temporary file
        unlink($temp_file);
        exit();
    }

    echo "File does not exist.";
    exit();
}

echo "Invalid request.";
exit();

9. Rename file

Renaming the file on FTP using PHP is very easy. You just have to provide 3 things:

  1. Folder name
  2. Old file name
  3. New file name
public function rename()
{
    $this->do_connect();

    $path = "/directory-name";
    $name = "new-file-name.php";
    $file = "old-file-name.php";

    // File to be renamed on the FTP server
    $remote_file = $path . "/" . $file;
    $remote_new_file = $path . "/" . $name;

    // Try to rename the file or folder
    if (!ftp_rename($this->conn_id, $remote_file, $remote_new_file))
    {
        echo json_encode([
            "status" => "error",
            "message" => "There was a problem renaming " . $file . " to " . $name
        ]);
        exit();
    }

    echo json_encode([
        "status" => "success",
        "message" => "Successfully renamed " . $file . " to " . $name
    ]);
    exit();
}

10. Delete file

Deleting a file from FTP in PHP is very simply. You just need to enter the full path of the file and call the PHP built-in ftp_delete function. Pass the FTP connection ID and file path as arguments.

public function delete_file()
{
    $this->do_connect();
    $path = "/directory-name/file-name.php";

    // Delete the file on the FTP server
    if (!ftp_delete($this->conn_id, $path))
    {
        echo json_encode([
            "status" => "error",
            "message" => "There was a problem while deleting " . $path
        ]);
        exit();
    }

    echo json_encode([
        "status" => "success",
        "message" => "Successfully deleted " . $path
    ]);
    exit();
}

11. Delete folder

Deleting a folder is NOT as simple as deleting a single file. There are 2 steps involved in deleting a folder from FTP in PHP.

  1. Recursively delete all files and folders inside that folder.
  2. Delete the folder itself.

So first we will create a function that will initialize the call to recursive function.

public function delete_folder()
{
    // Set maximum execution time to unlimited (0 means no limit)
    set_time_limit(0);

    $path = "/directory-path/folder-name";

    $this->do_connect();
    $this->ftp_delete_dir($path);

    echo json_encode([
        "status" => "success",
        "message" => "Folder has been deleted."
    ]);
    exit();
}

Our recursive function ftp_delete_dir will look like this:

// Function to recursively delete a directory
private function ftp_delete_dir($path)
{
    // Get the list of files in the directory
    $files = ftp_nlist($this->conn_id, $path);

    // Loop through each file
    foreach ($files as $file)
    {
        $file = basename($file);

        if ($file == '.' || $file == '..')
        {
            continue;
        }

        $file_path = "$path/$file";

        // If it's a directory, delete recursively
        if (@ftp_chdir($this->conn_id, $file_path))
        {
            ftp_chdir($this->conn_id, '..');
            ftpDelete($this->conn_id, $file_path);
        }
        else
        {
            // If it's a file, delete it
            ftp_delete($this->conn_id, $file_path);
        }
    }

    // Finally, remove the directory itself
    ftp_rmdir($this->conn_id, $path);
}

It does the following things:

  1. Loops through all the files inside that folder.
  2. Skip the “.” and “..” folders (they are just pointing towards current and parent directory respectively).
  3. If the file is a directory, start the recursion.
  4. Else delete the file.
  5. Finally at line #33, we are deleting the current directory itself.

So these are all the features we have in FTP manager I created in PHP and MySQL using Laravel framework. If you have any quetions regarding FTP or if you are having any problem, feel free to contact me.

File Manager in Laravel and React JS

A file manager web app is created in Laravel and React JS. We offer free 10 MB storage so you can test this script. Test it before you buy it. Easy deployment, you can just buy and upload the files on your server. Further instructions for deployment are in the file “README.md”. Check our tutorial if you need help in deployment.

We are using CloudBox Lite HTML template for this project.

Demo

Features

1) Authentication

I am using Laravel Sanctum API for handling authentication. It creates a token for each user and sends it in headers in AJAX requests. It is also useful so if you want to develop a mobile application for it, you can use the same authentication system. Because session authentication does not work on mobile.

2) Files and Folders

User can create as much folders as he wants and he can upload as much files as he wants unless his storage gets full. There is unlimited level of folder nesting just like in your computers, you can create folders and create folders inside it.

3) Rename

You can rename files and folders any time you want. You can also set the same name of different files in the same folder.

4) Private or public files

While uploading files, you can set if the file is publicly visible to other users. Or will it be only for you. You can share publicly available files with others.

User can change from public to private any time. Public files are saved in storage so they can be accessed by other users. While private files are saved in database in BLOB format. So they can only be accessible by the user who uploaded it.

5) Trash can

If you delete the file or folder by accident, it won’t be deleted permanently. It will be moved to trash where it remains unless you delete it. From trash can delete the file permanently or you can restore it. If you restore it, it will go to the same folder where it was before.

6) Share files

You can share files with other users as well if the file is public. While sharing file you can also set if the other user can just read it, or if he can modify the content of the file. Only text and source code file’s (txt, php, html, css, js, java, c, cpp, py, go, sql) content can be modified.

7) Realtime Collaboration

User can allow other’s to change the content of file without having to refresh the page. File owner can give write permission to a user and he will be able to edit the file. This is very useful for teams. Programmers can use this feature to work on the same project.

Making collaboration realtime using Node JS - File manager in Laravel and React JS
Making collaboration realtime using Node JS – File manager in Laravel and React JS

8) Profile

User can manage his personal information from his profile page. He can edit his name, phone and profile image. When user uploads a new profile image, we delete his old profile image. So only 1 image of user is saved in file system. The profile image is displayed when he shares a file with someone and also when someone adds him in his contact list.

9) Change Password

User can change his password. For that, he needs to enter his current password first. This is to prevent any other person to change his password. Passwords are stored using password_hash() PHP function that generates a store hash. It is a one-way hash, which means that once hashed, it cannot convert back to plain text. So even if someone sees your database, he won’t be able to tell the user’s passwords.

10) Email Settings

Now user can control when he wants to receive an email. Right now we are giving him 2 options:

  1. When someone add me in his contact list.
  2. When someone shares a file with me.

11) Contact List

If there are some people with whom you have files frequently. Then you do not need to type their email address everytime you share the file with them. Just add them in your contact list and next time you try to share a file with them, you will see a dropdown list with all your contacts. You can just pick the contact and hit “Share” button.

You can also see all the files you have shared with specific person from contact list.

Use React JS styles in Laravel blade template

If you are trying to give CSS styles in React JS inside Laravel blade template, but having the following error:

Use React JS styles in Laravel blade template

This happens when you try to give CSS styles in React JS in the following way:

function MyApp() {
    return (
        <h1 style={{
            color: "red"
        }}>Hello world</h1>
    )
}

ReactDOM.createRoot(
    document.getElementById("react-app")
).render(<MyApp />)

The error you are having is because the double curly braces {{ which are used in React JS for styling the tag, are also used by Laravel blade template to render the value of a PHP variable. Laravel will think of it as a PHP variable and will throw an error.

To fix this error, you need to create a separate object in your React JS component. That object will have all the styles for each tag. Modify your React JS component to the following:

function MyApp() {

    const styles = {
        heading: {
            color: "red"
        }
    }

    return (
        <h1 style={ styles.heading }>Hello world</h1>
    )
}

You can see that instead of setting the CSS directly in the style attribute, I have created a separate variable and used its value as a variable. This way your error gets fixed. Also, it will help you in setting CSS styles to multiple tags without duplicating them.

Share value between components – React JS

In this article, I will show you, how you can share value between multiple components in React JS. If you are new to React JS, check this tutorial to setup React JS in your project.

Step 1:

First, we are going to create a global state variable. This will be like a simple Javascript object.

<script>
    const globalState = {
        state: {
            user: null
        },
    }
</script>

In the state object, you can define all the variables, with their default values, that you want to share between components in React JS.

Step 2:

Then you need to create an array that will hold callback functions of all components for whom the value will be shared.

const globalState = {
    state: {
        user: null
    },

    listeners: [],
}

After that, we will create a function that will be called from the React JS component.

const globalState = {
    state: {
        user: null
    },

    listeners: [],

    listen (callback) {
        this.listeners.push(callback)
    },
}

This will accept a callback function that will be defined in the component (later in this tutorial). And that callback function will be pushed into the listeners array.

And create final method in this object will update the values of the state in this object. That function will also call the callback function of all the components are listening to this state. And inside that callback will send the new state object as well as the state currently updated in this call.

const globalState = {
    state: {
        user: null
    },

    listeners: [],

    listen (callback) {
        this.listeners.push(callback)
    },

    setState (newState) {
        const self = this

        this.state = {
            ...this.state,
            ...newState
        }

        this.listeners.forEach(function (callback) {
            callback(self.state, newState)
        })
    }
}

Step 3:

Now we need to create a component in React JS and set the state of this object.

<div id="header"></div>

<script type="text/babel">
    function Header() {
        React.useEffect(function () {
            globalState.setState({
                user: {
                    name: "Muhammad Adnan Afzal"
                }
            })
        }, [])

        return (
            <h1>Header</h1>
        )
    }

    ReactDOM.createRoot(
        document.getElementById("header")
    ).render(<Header />)
</script>
  1. First, we are updating the globalState.state object. Passing the object will update only the provided values. So even if your globalState has more variables in state object, this will only update the variables that are passed in setState method.
  2. This will also call all the listeners callback function from globalState as well. But right now, the listeners array is empty. It will only have value when some component listens to it.

Step 4:

We will create another component that will listen to this global state by calling the subscribe method.

<div id="content"></div>

<script type="text/babel">
    function Content() {
        const [state, setState] = React.useState(globalState.state)

        React.useEffect(function () {
            globalState.listen(function (newState, updatedState) {
                setState(newState)

                // check which state is updated
                if (typeof updatedState.user !== "undefined") {
                    //
                }
            })
        }, [])

        return (
            <>
                { state.user != null && (
                    <p>{ state.user.name }</p>
                )}

                <h1>Content</h1>
            </>
        )
    }

    ReactDOM.createRoot(
        document.getElementById("content")
    ).render(<Content />)
</script>
  1. First, we are creating a state variable and initializing it with the globalState.state variable. So, initially, the value of state inside Header component will be same as in globalState object.
  2. Then we are calling the subscribe method and passing a callback function in it.
  3. This callback function will only be called when the globalState.setState is called from Header component.
  4. When this callback is called, we are updating the state variable with what is received from Header component.

Now you will be able to view the user name in Content component, the user name that you have set from Header component. That’s how you can share value between components in React JS.

Complete code:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>State</title>

        <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
        
        <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.min.js"></script>
        
        <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.23.10/babel.js"></script>
    </head>

    <body>
        <script>
            const globalState = {
                state: {
                    user: null
                },

                listeners: [],

                listen (callback) {
                    this.listeners.push(callback)
                },

                setState (newState) {
                    const self = this

                    this.state = {
                        ...this.state,
                        ...newState
                    }

                    this.listeners.forEach(function (callback) {
                        callback(self.state, newState)
                    })
                }
            }
        </script>

        <div id="header"></div>

        <script type="text/babel">
            function Header() {
                React.useEffect(function () {
                    setTimeout(function () {
                        globalState.setState({
                            user: {
                                name: "Muhammad Adnan Afzal"
                            }
                        })
                    }, 1000)
                }, [])

                return (
                    <h1>Header</h1>
                )
            }

            ReactDOM.createRoot(
                document.getElementById("header")
            ).render(<Header />)
        </script>

        <div id="content"></div>

        <script type="text/babel">
            function Content() {
                const [state, setState] = React.useState(globalState.state)

                React.useEffect(function () {
                    globalState.listen(function (newState, updatedState) {
                        setState(newState)

                        // check which state is updated
                        if (typeof updatedState.user !== "undefined") {
                            //
                        }
                    })
                }, [])

                return (
                    <>
                        { state.user != null && (
                            <p>{ state.user.name }</p>
                        )}

                        <h1>Content</h1>
                    </>
                )
            }

            ReactDOM.createRoot(
                document.getElementById("content")
            ).render(<Content />)
        </script>
    </body>
</html>

Download

Show placeholder image in ReactJS

Imagine if you are displaying an image from the server in your React app. And the image gets deleted from the server. You do not want to show the broken image icon, as it does not look professional. You can show a placeholder image in your ReactJS App if the original image fails to load.

The following code will by default show the “Jackie Chan 2.jpg” image. If that image fails to load, it will render the “default-img.jpg” image inside the “img” folder.

Be careful: If the placeholder image does not exist as well, it will stuck in an infinite loop. To solve this problem, DO NOT save the placeholder image on the server. Always keep the placeholder images on the client side.

function MyApp() {
	const { useState } = React
	const [image, setImage] = useState("img/Jackie Chan 2.jpg")

	return (
		<>
			<h1>Hello React JS</h1>

			<img src={ image }
				style={{
					width: "100%"
				}}
				onError={function () {
					event.target.src = "img/default-img.jpg"
				}} />
		</>
	)
}

ReactDOM.createRoot(
	document.getElementById("app")
).render(<MyApp />)

As an example, you can use this image as a placeholder. Make sure to download it in your “img” directory. That’s how you can show a placeholder image in ReactJS if the original image fails to load. You can also read more articles on ReactJS.