Acceso a Datos con PDO y PostgreSQL

Resolución de ejercicios prácticos: Conexión, Consultas y API REST.

Preparación del Entorno (Tareas 1, 2 y 3)

Antes de programar, configuramos el servidor y la base de datos siguiendo estos pasos en la terminal de Linux (Ubuntu).

1. Instalación y Creación de Usuario

# Instalación
sudo apt-get install php8.3-pdo-pgsql postgresql

# Acceso a la consola y cambio de contraseña
sudo -u postgres psql
postgres=# alter user postgres password '123456';

2. Creación de la Base de Datos "Tienda"

-- Crear la BD
CREATE DATABASE tienda OWNER postgres;

-- Conectar a la BD
\c tienda

-- (Opcional) Ejemplo de estructura para la tabla producto
CREATE TABLE producto (
    id SERIAL PRIMARY KEY,
    nombre VARCHAR(100),
    precio DECIMAL(10,2),
    fabricante_id INT
);

-- Verificar
SELECT * FROM producto;

Ejercicio 1: Script de Conexión y Listado

Implementación básica de conexión a PostgreSQL usando la extensión PDO y visualización de datos en un array.

<?php
// Datos fijos de conexión
$host = 'localhost';
$dbname = 'tienda';
$username = 'postgres';
$password = '123456';

try {
    // Cadena de conexión (DSN) para PgSQL
    $dsn = "pgsql:host=$host;port=5432;dbname=$dbname;";
    
    // Crear instancia PDO
    $pdo = new PDO($dsn, $username, $password, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
    ]);

    echo "Conexión exitosa.<br>";

    // Consulta SQL
    $sql = "SELECT * FROM producto";
    $stmt = $pdo->query($sql);

    // Obtener datos en array asociativo
    $resultados = $stmt->fetchAll(PDO::FETCH_ASSOC);

    echo "<pre>";
    print_r($resultados);
    echo "</pre>";

} catch (PDOException $e) {
    echo "Error de conexión: " . $e->getMessage();
}
?>

Ejercicio 2: Conexión Interactiva por Formulario

Modificación del script para solicitar credenciales mediante POST, gestionar errores y contar filas devueltas.

<!-- VISTA: Formulario HTML -->
<form method="POST">
    <label>Servidor: <input type="text" name="host" value="localhost"></label><br>
    <label>Base de Datos: <input type="text" name="db" value="tienda"></label><br>
    <label>Usuario: <input type="text" name="user"></label><br>
    <label>Contraseña: <input type="password" name="pass"></label><br>
    <button type="submit" name="conectar">Conectar</button>
</form>

<?php
// LÓGICA PHP
if (isset($_POST['conectar'])) {
    $host = $_POST['host'];
    $db   = $_POST['db'];
    $user = $_POST['user'];
    $pass = $_POST['pass'];

    try {
        $dsn = "pgsql:host=$host;dbname=$db";
        $pdo = new PDO($dsn, $user, $pass);
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        echo "<h3 style='color:green'>Conectado correctamente a la BD</h3>";

        // Consultar productos
        $sql = "SELECT * FROM producto";
        $stmt = $pdo->query($sql);
        $filas = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        // Mostrar número de filas (rowCount)
        $num_filas = $stmt->rowCount();
        echo "<strong>La tabla productos contiene $num_filas filas.</strong><br><hr>";

        // Mostrar tabla HTML
        echo "<table border='1'>";
        foreach($filas as $fila) {
            echo "<tr>";
            echo "<td>" . $fila['nombre'] . "</td>";
            echo "<td>" . $fila['precio'] . " €</td>";
            echo "</tr>";
        }
        echo "</table>";

    } catch (PDOException $e) {
        echo "<h3 style='color:red'>Error: " . $e->getMessage() . "</h3>";
        echo "Por favor, revise los datos e inténtelo de nuevo.";
    }
}
?>

Ejercicio 3: Desarrollo de API REST JSON

Implementación de un servicio web que devuelve los productos en formato JSON. Soporta consultar todos los productos o filtrar por ID mediante peticiones GET.

Requisitos de la API:
  • Formato de respuesta: JSON (json_encode).
  • Consulta general: GET /api.php (Todos los productos).
  • Consulta por ID: GET /api.php?id=1 (Producto específico).
  • Seguridad: Uso de consultas parametrizadas (Prepared Statements).

Código del servicio (api.php)

<?php
// Cabecera para indicar que devolvemos JSON
header("Content-Type: application/json; charset=UTF-8");

// Configuración de BD
$host = 'localhost';
$db = 'tienda';
$user = 'postgres';
$pass = '123456';

try {
    $pdo = new PDO("pgsql:host=$host;dbname=$db", $user, $pass);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // Verificamos si nos pasan un ID por la URL
    if (isset($_GET['id'])) {
        // --- CASO 1: CONSULTA POR ID ---
        $sql = "SELECT * FROM producto WHERE id = :id";
        $stmt = $pdo->prepare($sql);
        // Vinculamos el parámetro para evitar inyección SQL
        $stmt->bindParam(':id', $_GET['id'], PDO::PARAM_INT);
        $stmt->execute();
        $resultado = $stmt->fetch(PDO::FETCH_ASSOC);
    } else {
        // --- CASO 2: CONSULTAR TODOS ---
        $sql = "SELECT * FROM producto";
        $stmt = $pdo->prepare($sql);
        $stmt->execute();
        $resultado = $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    // Devolvemos el resultado en formato JSON
    echo json_encode($resultado);

} catch (PDOException $e) {
    // En caso de error, devolvemos un JSON con el mensaje
    echo json_encode(["error" => "Error de conexión: " . $e->getMessage()]);
}
?>

Prueba con Postman

Para verificar el funcionamiento, lanzamos peticiones GET a la URL del script: