What You'll Build: A PHP Webservice Overview
To create a webservice using PHP, you build a server-side application that exposes data and functionality over HTTP, allowing client applications to interact with a MySQL database through standardized requests. This tutorial covers two approaches: a RESTful API (using JSON) and a SOAP webservice (using XML), implementing full CRUD (Create, Read, Update, Delete) operations with security best practices enforced throughout.
Requirements for Creating a PHP Webservice
Before you start, ensure you have the following tools installed and configured:
- A web server (Apache or Nginx) to serve your PHP files
- Composer for autoloading and dependency management
- Postman (or cURL) for testing API endpoints
- A text editor or IDE (VS Code, PHPStorm, etc.)
Step 1: Setting Up the PHP Environment
Install PHP and configure it to work with your web server. The easiest way is to use XAMPP (Apache + MySQL + PHP) or WAMP on Windows, or LAMP on Linux.
- Download and install XAMPP from the official Apache Friends website.
- Start the Apache and MySQL modules from the XAMPP control panel.
- Locate the
php.inifile (typically inC:\xampp\php\php.ini) and ensure these extensions are uncommented:extension=pdo_mysql,extension=soap,extension=openssl. - Set
display_errors = Onfor development (turn off in production). - Create a test file
test.phpin the web root (C:\xampp\htdocs\) with the content<?php phpinfo(); ?>. - Open
http://localhost/test.phpin your browser. If you see the PHP info page, your environment is ready.
Step 2: Creating the Project Structure
Organize your webservice project into a clean, maintainable directory structure with separation of concerns.
- Create a root directory for your project, e.g.,
my-webservice/. - Inside it, create these folders:
public/, the web root (containsindex.php)src/, application code (controllers, models)config/, database and API configurationcontrollers/, request handlersmodels/, database interaction classes
- Create a
composer.jsonfile in the root with autoload configuration:
{
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
"require": {
"php": ">=7.4"
}
}
Run composer dump-autoload to generate the autoloader.
Step 3: Setting Up the MySQL Database
Create a database and table to store your data. Use phpMyAdmin (included with XAMPP) or the MySQL command line.
- Create a database named
webservice_db. - Run this SQL to create a
userstable:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Create a PDO connection script in config/database.php:
<?php
class Database {
public $conn;
public function getConnection() {
$this->conn = null;
try {
$this->conn = new PDO("mysql:host=" . $this->host . ";dbname=" . $this->dbname, $this->user, $this->pass);
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
error_log("Connection error: " . $e->getMessage()); // Log, don't expose
http_response_code(500);
echo json_encode(["error" => "Database connection failed"]);
exit;
}
return $this->conn;
}
}
?>
Step 4: Building RESTful API Endpoints
Create a front controller in public/index.php that routes requests to the appropriate handler based on the URL and HTTP method.
- Set the content type to JSON and enable CORS headers.
- Parse the request URI to determine the endpoint (e.g.,
/usersor/users/1). - Route based on HTTP method (GET, POST, PUT, DELETE).
<?php
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$segments = explode('/', trim($uri, '/'));
$resource = $segments[0] ?? '';
$id = $segments[1] ?? null;
$method = $_SERVER['REQUEST_METHOD'];
$controller = new UserController();
switch ($resource) {
case 'users':
switch ($method) {
case 'GET':
$id ? $controller->readOne($id) : $controller->readAll();
break;
case 'POST':
$controller->create();
break;
case 'PUT':
$controller->update($id);
break;
case 'DELETE':
$controller->delete($id);
break;
default:
http_response_code(405);
echo json_encode(["error" => "Method not allowed"]);
}
break;
default:
http_response_code(404);
echo json_encode(["error" => "Endpoint not found"]);
}
?>
Step 5: Implementing CRUD Operations with PHP
Create the UserController class in src/controllers/ that handles each CRUD operation using PDO prepared statements.
- Create, Validate input, sanitize, and insert a new record.
- Read, Fetch all records or a single record by ID.
- Update, Modify an existing record.
- Delete, Remove a record.
<?php
class UserController {
private $conn;
private $table = "users";
public function __construct() {
$db = new Database();
$this->conn = $db->getConnection();
}
public function create() {
$data = json_decode(file_get_contents("php://input"), true);
// Validate input
$name = filter_var($data['name'] ?? '', FILTER_SANITIZE_STRING);
$email = filter_var($data['email'] ?? '', FILTER_VALIDATE_EMAIL);
if (!$name || !$email) {
http_response_code(400);
echo json_encode(["error" => "Invalid name or email"]);
return;
}
$query = "INSERT INTO " . $this->table . " (name, email) VALUES (:name, :email)";
$stmt = $this->conn->prepare($query);
$stmt->bindParam(':name', $name);
$stmt->bindParam(':email', $email);
if ($stmt->execute()) {
http_response_code(201);
echo json_encode(["message" => "User created", "id" => $this->conn->lastInsertId()]);
} else {
http_response_code(500);
echo json_encode(["error" => "Unable to create user"]);
}
}
public function readAll() {
$query = "SELECT * FROM " . $this->table;
$stmt = $this->conn->prepare($query);
$stmt->execute();
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($users);
}
public function readOne($id) {
$query = "SELECT * FROM " . $this->table . " WHERE id = :id";
$stmt = $this->conn->prepare($query);
$stmt->bindParam(':id', $id);
$stmt->execute();
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if ($user) {
echo json_encode($user);
} else {
http_response_code(404);
echo json_encode(["error" => "User not found"]);
}
}
public function update($id) {
$data = json_decode(file_get_contents("php://input"), true);
$name = filter_var($data['name'] ?? '', FILTER_SANITIZE_STRING);
$email = filter_var($data['email'] ?? '', FILTER_VALIDATE_EMAIL);
$query = "UPDATE " . $this->table . " SET name = :name, email = :email WHERE id = :id";
$stmt = $this->conn->prepare($query);
$stmt->bindParam(':name', $name);
$stmt->bindParam(':email', $email);
$stmt->bindParam(':id', $id);
if ($stmt->execute()) {
echo json_encode(["message" => "User updated"]);
} else {
http_response_code(500);
echo json_encode(["error" => "Unable to update user"]);
}
}
public function delete($id) {
$query = "DELETE FROM " . $this->table . " WHERE id = :id";
$stmt = $this->conn->prepare($query);
$stmt->bindParam(':id', $id);
if ($stmt->execute()) {
echo json_encode(["message" => "User deleted"]);
} else {
http_response_code(500);
echo json_encode(["error" => "Unable to delete user"]);
}
}
}
?>
Step 6: Adding Authentication and Security
Secure your webservice with API key authentication, HTTPS enforcement, input sanitization, and rate limiting.
- API Key Authentication: Generate a secret key (e.g.,
my_secret_api_key_123) and store it inconfig/config.php. Check theX-API-Keyheader on every request. - HTTPS Enforcement: In production, redirect all HTTP traffic to HTTPS using server configuration or PHP headers.
- Input Sanitization: Always use
filter_var()and prepared statements to prevent SQL injection and XSS.
// Add to public/index.php at the top
if ($apiKey !== $validKey) {
http_response_code(401);
echo json_encode(["error" => "Unauthorized"]);
exit;
}
// Rate limiting (simple example)
$clientIP = $_SERVER['REMOTE_ADDR'];
$currentTime = time();
$windowStart = $currentTime - 3600;
$requests = file_exists($cacheFile) ? json_decode(file_get_contents($cacheFile), true) : [];
$requests = array_filter($requests, function($timestamp) use ($windowStart) { return $timestamp > $windowStart; });
$requests[] = $currentTime;
file_put_contents($cacheFile, json_encode($requests));
Step 7: Creating a SOAP Webservice with PHP
The PHP SOAP extension supports SOAP 1.1, SOAP 1.2, and WSDL 1.1 (but not WSDL 2.0). Create a WSDL file that defines your service contract, then instantiate SoapServer.
- Create a WSDL file
service.wsdlthat defines the operations (e.g.,getUser,createUser), their parameters, and return types. - Create a PHP class with the business logic for each operation.
- Instantiate the server and handle requests.
<?php
$options = ['uri' => 'http://localhost/my-webservice/service.php'];
$server = new SoapServer(null, $options); // Non-WSDL mode
$server->setClass('UserService');
$server->handle();
?>
For WSDL mode, use $server = new SoapServer("path/to/service.wsdl"); and add functions with $server->addFunction() or $server->setClass().
Step 8: Testing Your PHP Webservice
Test all endpoints using cURL commands or Postman, and verify expected responses.
- Create a user (POST):
curl -X POST -H "Content-Type: application/json" -H "X-API-Key: my_secret_api_key_123" -d '{"name":"Alice","email":"alice@example.com"}' http://localhost/my-webservice/public/users, Expected: 201 with message. - Read all users (GET):
curl -H "X-API-Key: my_secret_api_key_123" http://localhost/my-webservice/public/users, Expected: JSON array. - Read one user (GET):
curl -H "X-API-Key: my_secret_api_key_123" http://localhost/my-webservice/public/users/1, Expected: JSON object. - Update a user (PUT):
curl -X PUT -H "Content-Type: application/json" -H "X-API-Key: my_secret_api_key_123" -d '{"name":"Alice Updated","email":"alice.new@example.com"}' http://localhost/my-webservice/public/users/1, Expected: 200 with message. - Delete a user (DELETE):
curl -X DELETE -H "X-API-Key: my_secret_api_key_123" http://localhost/my-webservice/public/users/
















