Guide Area
Guidearea banner

Create a REST web service in PHP – part I (Basics)

Web services are very important in many cases, for example in Android where web service is the most used option to connect to a database other than SQLite. In this tutorial, I will show you how to create a simple PHP REST web service which you will be able to access and get results in JSON format. You do not need to have any advanced experience with PHP. I will be using only simple PHP commands that you will understand with no PHP coding experience.

Step 1. Create your web hosting

In order to connect to web service, you will have to place your PHP files publicly, somewhere on internet. You will need a hosting service.

It is up to you if you choose one with domain, or SSL certificates, or none of them. Most of the free hosting providers will provide you with a third-level domain name, such as “mydomain.xyz.com”. Free hostings are nice for beginnings, but are often limited by speed and capacity. You will not need a lot of space right now, but if you decide to store images or other files later, you should invest some money in a paid web hosting. The free version will be perfectly fine for now and I will use the domain above in my code snippets. SSL certificate will give you extra security, as it brings the HTTPS protocol in play, but will cost you a lot of money (the cheapest ones from 50-70 EUR per year).

I have been using Hostinger.com for past half year and I can recommend it fully, as they have an excellent support and I have never had any problem with configurations, or so. The only issue that might arise is PHP extensions, but I think that after a short talk with them, they will be able to help you with it if you are on a paid plan. They offer free hostings too, so it is certainly a good start. Of course, you can take a look at others and select your own desired hosting.

Step 2. Prepare the file structure

There will be four files that I will be creating. Each of them will have a specific purpose. Let’s take a look:

  • ws.php – The main web service file, which you will call from your apps/websites
  • config.inc.php – The file with database configuration
  • functions.inc.php – The file with my custom functions
  •  .htaccess – An Apache access control file, which I use to protect my web service files

There is probably no file that needs an explanation, except the .htaccess. The way my web service works is that whenever I call my controller file – ws.php, this file gets the database connection from config.inc.php and my custom functions from functions.inc.php. These two files should not be visible from outside. If they are, I risk that both my database credentials and my custom functions with sensitive information will be revealed.That is why in .htaccess I only allow access to my controller file. People can access this file and see its contents, as there is not anything that I consider sensitive.

There is many ways how to hack web services, but I will not try to protect against all of them – unfortunately, I am not a security professional. Although, with .htaccess, I will achieve at least basic level of security.

Step 3. Prepare the database connection

Go to your new hosting and create a new MySQL database. Call it vladmarton_test. Go inside and create a new table with name ‘users’ and columns ‘id’ of type integer(11) and ‘name’ of type varchar(255). After you are done, go back to your PHP editor. If you do not have any by now, there is a lot of lightweight editors such as PSPad, or the ones with a lot of functionality, such as my favourite PHPStorm from JetBrains.

So the first file I will create will be called config.inc.php. I will be using PDO connection, because it is the newest and most advanced SQL connector naturally available in PHP. Here is the code that you will paste inside:

<?php
$db_servername = "db.mydomain.xyz.com";
$db_username = "username";
$db_password = "password";
$db_dbname = "vladmarton_test";

try {
    $conn = new PDO("mysql:host=$db_servername;dbname=$db_dbname", $db_username, $db_password);
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    die("OOPs something went wrong");
}
?>

What happens here is that I create four variables. I store my database connection credentials in them and then use them to create a new PDO database connection object. In addition, I set the connection attribute called ‘ATTR_ERRMODE’ to value ‘ERRMODE_EXCEPTION’. What it means is that when connection runs into error, it will return exception, specifically (More about ATTR_ERRMODE here).

I will use the $conn PDO object in my other files, therefore if there is an error with database connection, it will return exception before I manage to do my tasks.

Step 4. Write custom functions

Since we already have a table called users, with columns id and name, I will write two functions that will be able to insert and remove user to/from this table. In order to avoid concurrency problems, I will execute all of my statements in transactions. PDO’s transactions automatically lock the tables, so while the transaction is not finished, no other user can insert/delete/update rows in this table. You can read more about PDO transactions here. Create the file functions.inc.php and insert these two snippets:

<?php

function insert_user($conn,$userid,$username) {
    try {
        $conn->beginTransaction();
        $sql = 'INSERT INTO users VALUES(:userid, :username)';
        $stmt = $conn->prepare($sql);
        $stmt->bindParam(':userid', $userid, PDO::PARAM_INT);
        $stmt->bindParam(':username', $username, PDO::PARAM_STR);
        $stmt->execute();
        $conn->commit();
    } catch (Exception $e) {
        $conn->rollBack();
        echo $e->getMessage();
    }
}
function delete_user($conn,$userid) {
    try {
        $conn->beginTransaction();
        $sql = 'DELETE FROM users WHERE id = :userid';
        $stmt = $conn->prepare($sql);
        $stmt->bindParam(':userid', $userid, PDO::PARAM_INT);
        $stmt->execute();
        $conn->commit();
    } catch (Exception $e) {
        $conn->rollBack();
        echo $e->getMessage();
    }
}

?>

Explanation:

The file config.inc.php, where our $conn objects is located, will be included into ws.php file, from which we will call these two functions. In order to use the $conn variable in the functions, we need to pass it to each function as a parameter.

There is another approach – I could include the config.inc.php file inside of my functions.inc.php file. It would be easier because I would not have to pass the connection as a variable. The only problem is that your functions.inc.php file might have hundreds of functions and half of them might not need to use database at all. Since the config.inc.php would get included at all times, your web service would create a new database connection even if your wanted to simply return an image from your hosting storage. It would not cause any problems, although it is not the right approach.

I insert my variables using ‘:’ sign. Statement $stmt will search the $sql string for any occurrence of ‘:userid’ and ‘:username’, and will replace it with the values from function parameters. This approach is very safe, because the parameter binding prevents SQL injections by converting any user input into SQL variable, and never a command.

Transactions always wait until all commands inside of them are finished without any error. If any of the statement execution fails (you can have more of them inside one transaction), the transaction will be reversed and all changed data will be reset to previous state, hence the rollBack() function. If they succeed, the changes will be committed, hence the commit() function.

Step 5. Introduction to ws.php (controller file)

This file is a root of my new web service. Imagine that you want to create a new user from your application. Your desired user should have an automatically generated ID and name “Stuart Little”. All I have to do in this case is to call the right URL with the right parameters. There are more types of URL requests, you can read a nice comparison here. For the sake of simplicity, I will use GET request type. Therefore, I will call this URL:

http://mydomain.xyz.com/ws.php?action=insertuser&id=1&name=Stuart%20Little

I am sure there are two weird things that you noticed. The first are the URL dividers. Character ‘?’ means that you are finished with the file name and you are going to specify parameters and their values. Character ‘&’ splits the parameters, so you can use more at the same time.

The second thing is the ‘%20’ shortcode. As I told you above, there are certain URL characters that you cannot use in your strings, such as ‘?’ and ‘&’. You can always encode all the string to Base64 before you call the URL, which will make it easier, but each string will become 33% longer (that is how Base64 works). For now, it is enough if you replace your special signs with the short-codes from this link.

Step 6. Create the controller file

Because you now understand how the web service will work, I will go ahead and create a new file called ws.php with this code inside of it:

<?php

require 'config.inc.php';
require 'functions.inc.php';

$action = $_GET['action'];
$id = $_GET['id'];
$name = $_GET['name'];

$name = str_replace('%20', ' ', $name);

switch ($action) {
    case 'insertuser':
        insert_user($conn, $id, $name);
        break;
    case 'delete_user':
        delete_user($conn, $id);
        break;
    default:
        echo 'Action not recognized';
        break;
}

?>

With the logic from step 5, we should now check the $name variable for any ‘%20’ shortcodes. We use function str_replace() to replace this short-code with a space. Later on, we assign function calls to each of supported actions (right now just insertuser and deleteuser). If the action is not named properly in our URL address, the web service returns string ‘Action not recognized’. Easy peasy! My web service is almost done, although it is ready to use, even without proceeding to the next, last step! If you feel like testing already, you can call the URL using any browser and check the changes in the database.

PS: Watch the browser response after entering the URL. If there will be any exception, it is right there where the exception will appear.

Step 7. (Last) Secure the files using .htaccess

The last step is very easy. I will populate the .htaccess file with a few lines. These lines will disable access from all files while allowing access to only one – ws.php file.

# hide all files
<Files ~ "^.*">
  Deny from all
</Files>

# allow only one file
<Files ws.php>
Allow from all
Satisfy any
</Files>

Save and put this file next to ws.php and try to open your browser and enter this URL:

http://mydomain.xyz.com/config.inc.php

What you will see is an error:

Forbidden

You don't have permission to access config.inc.php on this server.

The only file that will be accessible from now on is the controller file.

Conclusion

Voila! Your web service is now ready to be used and you can call it from any platform that has an internet connection! It might be a bit long to understand, but the concept is very easy and you will get used to it fairly quickly. In the next part of this tutorial I will show you how to make a custom encryption system, in case you do not have an SSL certificate, but want to secure your data yourself. Meanwhile, check my article about sending multiple images at once from PHP to Android. If you have any question, leave a comment below!

Vladimir Marton

DevOps Engineer focused on cloud infrastructure, automation, CI/CD and programming in Javascript, Python, PHP and SQL. Guidearea is my oldest project where I write articles about programming, marketing, SEO and others.

1 comment