My todo list
PHP api.
Simple server api.
php
<?php
$host = '127.0.0.1';
$port = '3306';
$user = '';
$password = '';
try {
$schemaName = 'MyDB';
$pdo = new PDO("mysql:host=$host;port=$port;dbname=$schemaName", $user, $password);
$result = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$input = json_decode(file_get_contents('php://input'), true);
$sqlQuery = '';
$result['action'] = $input['action'];
switch ($input['action']) {
case "insert":
$sqlQuery = "INSERT INTO Todo (todo) VALUES (:todo)";
$pdoQuery = $pdo->prepare($sqlQuery);
$pdoQuery->execute(['todo' => $input['todo']]);
$result['data'] = $pdo->lastInsertId();
break;
case "update":
$sqlQuery = "UPDATE Todo SET done= :done WHERE id= :id";
$pdoQuery = $pdo->prepare($sqlQuery);
$pdoQuery->execute(['done' => $input['done'], 'id' => $input['id']]);
break;
case "delete":
$sqlQuery = "DELETE FROM Todo WHERE id= :id";
$pdoQuery = $pdo->prepare($sqlQuery);
$pdoQuery->execute(['id' => $input['id']]);
break;
case "get":
$sqlQuery = "SELECT * FROM Todo";
$res = $pdo->query($sqlQuery);
$result['data'] = $re
$result['status'] = 'Ok';
} else {
$result["status"] = "error";
$result["message"] = "Method not allowed. Use POST";
}
} catch (Exception $e) {
$result["status"] = "error";
$result["message"] = $e->getMessage();
}
header('Content-Type: application/json; charset=utf-8');
echo json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
$pdo = null;
?>Client access
Using fetch index.php
html
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Todo List</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-SgOJa3DmI69IUzQ2PVdRZhwQ+dy64/BUtbMJw1MZ8t5HZApcHrRKUc4W0kG879m7" crossorigin="anonymous">
</head>
<body>
<nav class="navbar navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand">My todo list</a>
</div>
</nav>
<div class="container mt-4">
<div class="input-group mb-3">
<input id="txt-input" type="text" class="form-control" placeholder="Todo" aria-label="Recipient's username" aria-describedby="button-addon2">
<button class="btn btn-primary" type="button" id="button-addon">add</button>
</div>
<div id="todoList" class="list-group"></div>
</div>
</div>
<script>
const elTodoList = document.querySelector('#todoList')
const elBtn = document.querySelector('#button-addon')
const elTxt = document.querySelector('#txt-input')
let html = itemTodo => `
<div class="_item list-group-item d-flex align-items-center list-group-item-action" itemid="${itemTodo.id}">
<img src="${ itemTodo.done != 0 ? 'check.svg' : 'minus.svg' }" class="me-2" alt="check" height="25">
<span class="flex-grow-1">${itemTodo.todo}</span>
<img class="_cancel" src="cancel.svg" alt="check" height="25">
</div>
`
let data = []
elBtn.addEventListener('click', async e => {
let res = await TodoAPI({ action: 'insert', todo: elTxt.value })
if (res.status == 'Ok') {
let newItem = { id:res.data, todo: elTxt.value, done: 0 }
data.push(newItem)
elTodoList.insertAdjacentHTML('beforeend', html(newItem))
}
console.log(res)
elTxt.value = ''
})
elTodoList.addEventListener('click', async e => {
let elParent = e.target.parentElement
let res
if (elParent.classList.contains('_item')){
let item = data.find(item => item.id == elParent.attributes.itemid.value)
if (e.target.classList.contains('_cancel')){
data.splice(data.indexOf(item), 1)
res = await TodoAPI({ action: 'delete', id: item.id })
} else {
item.done = item.done == 0 ? 1: 0
res = await TodoAPI({ action: 'update', done: item.done, id: item.id })
}
console.log(res)
elTodoList.innerHTML = ''
data.forEach( item => {
elTodoList.insertAdjacentHTML('beforeend', html(item))
})
}
})
async function TodoAPI(query) {
const result = await fetch('/todo_api.php', {
method: 'POST',
headers: {
'content-Type': 'application/json'
},
body: JSON.stringify(query) //{ action: 'query', query: 'SELECT * FROM Todo'})
})
return await result.json()
}
async function Init() {
const res = await TodoAPI({ action: 'get' })
if (res.status == 'Ok') {
data = res.data
data.forEach( item => {
elTodoList.insertAdjacentHTML('beforeend', html(item))
})
}
console.log(res)
}
Init()
</script>
</body>
</html>
}WebSocket
Ratchet
WebSockets for PHP
sh
sudo apt update
sudo apt install composerCreate project
sh
composer init --require=cboden/ratchet --no-interactionInstall Ratchet
sh
composer require cboden/ratchetServer.php
php
<?php
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Http\HttpServer;
use Ratchet\Server\IoServer;
use Ratchet\WebSocket\WsServer;
require dirname(__DIR__) . '/html/vendor/autoload.php';
class Chat implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
echo "Servidor WebSocket iniciado\n";
}
public function onOpen(ConnectionInterface $conn) {
$this->clients->attach($conn);
echo "Nova conexão: {$conn->resourceId}\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
foreach ($this->clients as $client) {
if ($from !== $client) {
$client->send($msg);
}
}
echo "Mensagem recebida: $msg\n";
}
public function onClose(ConnectionInterface $conn) {
$this->clients->detach($conn);
echo "Conexão fechada: {$conn->resourceId}\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "Erro: {$e->getMessage()}\n";
$conn->close();
}
}
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Chat()
)
),
8080
);
$server->run();bash
sh
php server.phpNginx setup
sh
server {
listen 80;
server_name your-domain.com;
# Configuração para PHP (FastCGI)
location / {
root /home/srvpi/Public/websocket-php/public; # Ajuste para o caminho correto
index index.php index.html;
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.1-fpm.sock; # Ajuste para sua versão do PHP
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Configuração para WebSocket
location /ws {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 86400;
}
}