N. Carpeta « php »

Versión para imprimir.

A. php / Bd.php

1
<?php
2
3
require_once __DIR__ . "/ROL_ID_CLIENTE.php";
4
require_once __DIR__ . "/ROL_ID_ADMINISTRADOR.php";
5
require_once __DIR__ . "/lib/rolBusca.php";
6
require_once __DIR__ . "/lib/rolAgrega.php";
7
require_once __DIR__ . "/lib/usuRolAgrega.php";
8
require_once __DIR__ . "/usuarioBuscaSan.php";
9
10
class Bd
11
{
12
13
 private static ?PDO $pdo = null;
14
15
 static function pdo(): PDO
16
 {
17
  if (self::$pdo === null) {
18
19
   self::$pdo = new PDO(
20
    // cadena de conexión
21
    "sqlite:" . __DIR__ . "/srvaut.db",
22
    // usuario
23
    null,
24
    // contraseña
25
    null,
26
    // Opciones: pdos no persistentes y lanza excepciones.
27
    [PDO::ATTR_PERSISTENT => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
28
   );
29
30
   self::$pdo->exec(
31
    'CREATE TABLE IF NOT EXISTS USUARIO (
32
      USU_ID INTEGER,
33
      USU_SAN TEXT NOT NULL,
34
      USU_SEN TEXT NOT NULL,
35
      CONSTRAINT USU_PK
36
       PRIMARY KEY(USU_ID),
37
      CONSTRAINT USU_SAN_UNQ
38
       UNIQUE(USU_SAN),
39
      CONSTRAINT USU_SAN_NV
40
       CHECK(LENGTH(USU_SAN) > 0)
41
     )'
42
   );
43
   self::$pdo->exec(
44
    'CREATE TABLE IF NOT EXISTS ROL (
45
      ROL_ID TEXT NOT NULL,
46
      ROL_DESCRIPCION TEXT NOT NULL,
47
      CONSTRAINT ROL_PK
48
       PRIMARY KEY(ROL_ID),
49
      CONSTRAINT ROL_ID_NV
50
       CHECK(LENGTH(ROL_ID) > 0),
51
      CONSTRAINT ROL_DESCR_UNQ
52
       UNIQUE(ROL_DESCRIPCION),
53
      CONSTRAINT ROL_DESCR_NV
54
       CHECK(LENGTH(ROL_DESCRIPCION) > 0)
55
     )'
56
   );
57
   self::$pdo->exec(
58
    'CREATE TABLE IF NOT EXISTS USU_ROL (
59
       USU_ID INTEGER NOT NULL,
60
       ROL_ID TEXT NOT NULL,
61
       CONSTRAINT USU_ROL_PK
62
        PRIMARY KEY(USU_ID, ROL_ID),
63
       CONSTRAINT USU_ROL_USU_FK
64
        FOREIGN KEY (USU_ID) REFERENCES USUARIO(USU_ID),
65
       CONSTRAINT USU_ROL_ROL_FK
66
        FOREIGN KEY (ROL_ID) REFERENCES ROL(ROL_ID)
67
      )'
68
   );
69
70
   self::$pdo->beginTransaction();
71
72
   if (rolBusca(self::$pdo, "Administrador") === false) {
73
    rolAgrega(
74
     bd: self::$pdo,
75
     id: "Administrador",
76
     descripcion: "Administra el sistema."
77
    );
78
   }
79
80
   if (rolBusca(self::$pdo, "Cliente") === false) {
81
    rolAgrega(
82
     bd: self::$pdo,
83
     id: "Cliente",
84
     descripcion: "Realiza compras."
85
    );
86
   }
87
88
   $usuarioAgrega = self::$pdo->prepare(
89
    "INSERT INTO USUARIO (
90
        USU_SAN, USU_SEN
91
       ) VALUES (
92
        :USU_SAN, :USU_SEN
93
       )"
94
   );
95
96
   if (usuarioBuscaSan(self::$pdo, "pepito") === false) {
97
    $usuarioAgrega->execute([
98
     ":USU_SAN" => "pepito",
99
     ":USU_SEN" => password_hash("cuentos", PASSWORD_DEFAULT),
100
    ]);
101
    $usuId = self::$pdo->lastInsertId();
102
    usuRolAgrega(self::$pdo, $usuId, [ROL_ID_CLIENTE]);
103
   }
104
105
   if (usuarioBuscaSan(self::$pdo, "susana") === false) {
106
    $usuarioAgrega->execute([
107
     ":USU_SAN" => "susana",
108
     ":USU_SEN" => password_hash("alegria", PASSWORD_DEFAULT),
109
    ]);
110
    $usuId = self::$pdo->lastInsertId();
111
    usuRolAgrega(self::$pdo, $usuId, [ROL_ID_ADMINISTRADOR]);
112
   }
113
114
   if (usuarioBuscaSan(self::$pdo, "bebe") === false) {
115
    $usuarioAgrega->execute([
116
     ":USU_SAN" => "bebe",
117
     ":USU_SEN" => password_hash("saurio", PASSWORD_DEFAULT),
118
    ]);
119
    $usuId = self::$pdo->lastInsertId();
120
    usuRolAgrega(self::$pdo, $usuId, [ROL_ID_CLIENTE,ROL_ID_ADMINISTRADOR]);
121
   }
122
123
   self::$pdo->commit();
124
  }
125
126
  return self::$pdo;
127
 }
128
}
129

B. php / jsonMiNav.php

1
<?php
2
3
function jsonMiNav(string $san, array $rolIds)
4
{
5
 $json = [
6
  "ocupado" => ["hidden" => true],
7
  "aIndex" => ["hidden" => false],
8
  "aAdmin" => [
9
   "hidden" => array_search(ROL_ID_ADMINISTRADOR, $rolIds, true) === false
10
  ],
11
  "aCliente" => [
12
   "hidden" => array_search(ROL_ID_CLIENTE, $rolIds, true) === false
13
  ],
14
  "san" => [
15
   "hidden" => $san === "",
16
   "textContent" => $san
17
  ],
18
  "aPerfil" => ["hidden" => false],
19
 ];
20
21
 return $json;
22
}
23

C. php / login.php

1
<?php
2
3
require_once __DIR__ . "/lib/manejaErrores.php";
4
require_once __DIR__ . "/lib/BAD_REQUEST.php";
5
require_once __DIR__ . "/lib/recibeTextoObligatorio.php";
6
require_once __DIR__ . "/lib/recibeTexto.php";
7
require_once __DIR__ . "/lib/devuelveJson.php";
8
require_once __DIR__ . "/lib/rolIdsParaUsuId.php";
9
require_once __DIR__ . "/SAN.php";
10
require_once __DIR__ . "/USU_ID.php";
11
require_once __DIR__ . "/ROL_IDS.php";
12
require_once __DIR__ . "/Bd.php";
13
require_once __DIR__ . "/protegeLogin.php";
14
require_once __DIR__ . "/usuarioBuscaSan.php";
15
16
list($san, $rolIds) = protegeLogin([]);
17
18
$san = recibeTextoObligatorio("san");
19
$sen = recibeTexto("sen");
20
21
$bd = Bd::pdo();
22
23
$usuario = usuarioBuscaSan($bd, $san);
24
25
if (
26
 $usuario === false
27
 || !password_verify(
28
  ($sen === false || $sen === null) ? "" : $sen,
29
  $usuario["USU_SEN"]
30
 )
31
)
32
 throw new ProblemDetailsException([
33
  "status" => BAD_REQUEST,
34
  "type" => "/errors/datosincorrectos.html",
35
  "title" => "Datos incorrectos.",
36
  "detail" => "El san y/o el sen proporcionados son incorrectos.",
37
 ]);
38
39
$_SESSION[SAN] = $san;
40
$_SESSION[USU_ID] = $usuario[USU_ID];
41
42
devuelveJson([
43
 SAN => $san,
44
 ROL_IDS => rolIdsParaUsuId($bd, $usuario[USU_ID])
45
]);
46

D. php / logout.php

1
<?php
2
3
require_once __DIR__ . "/lib/manejaErrores.php";
4
require_once __DIR__ . "/lib/devuelveNoContent.php";
5
require_once __DIR__ . "/SAN.php";
6
require_once __DIR__ . "/ROL_IDS.php";
7
8
session_start();
9
10
if (isset($_SESSION[SAN])) {
11
 unset($_SESSION[SAN]);
12
}
13
if (isset($_SESSION[ROL_IDS])) {
14
 unset($_SESSION[ROL_IDS]);
15
}
16
17
session_destroy();
18
19
devuelveNoContent();
20

E. php / protege.php

1
<?php
2
3
require_once __DIR__ . "/lib/NO_AUTORIZADO.php";
4
require_once __DIR__ . "/lib/ProblemDetailsException.php";
5
require_once __DIR__ . "/lib/rolIdsParaUsuId.php";
6
require_once __DIR__ . "/SAN.php";
7
require_once __DIR__ . "/USU_ID.php";
8
require_once __DIR__ . "/Bd.php";
9
10
function protege(array $rolIdsPermitidos)
11
{
12
13
 session_start();
14
15
 $san = isset($_SESSION[SAN]) ? $_SESSION[SAN] : "";
16
 $usuId = isset($_SESSION[USU_ID]) ? $_SESSION[USU_ID] : -1;
17
 $rolIds = rolIdsParaUsuId(Bd::pdo(), $usuId);
18
19
 if (count($rolIdsPermitidos) === 0) {
20
21
  return [$san, $rolIds, $usuId];
22
 } else {
23
24
  if ($san === "")  throw creaNoAutorizado();
25
26
  foreach ($rolIdsPermitidos as $rolId) {
27
   if (array_search($rolId, $rolIds, true) !== false) {
28
    return [$san, $rolIds, $usuId];
29
   }
30
  }
31
32
  throw creaNoAutorizado();
33
 }
34
}
35
36
function creaNoAutorizado()
37
{
38
 return new ProblemDetailsException([
39
  "status" => NO_AUTORIZADO,
40
  "type" => "/errors/noautorizado.html",
41
  "title" => "No autorizado.",
42
  "detail" => "No estás autorizado para usar este recurso.",
43
 ]);
44
}
45

F. php / protegeLogin.php

1
<?php
2
3
require_once __DIR__ . "/lib/NO_AUTORIZADO.php";
4
require_once __DIR__ . "/lib/ProblemDetailsException.php";
5
require_once __DIR__ . "/protege.php";
6
7
function protegeLogin(array $rolIdsPermitidos)
8
{
9
10
 list($san, $rolIds, $usuId) = protege($rolIdsPermitidos);
11
12
 if ($san !== "")
13
  throw new ProblemDetailsException([
14
   "status" => NO_AUTORIZADO,
15
   "type" => "/errors/sesioniniciada.html",
16
   "title" => "Sesión iniciada.",
17
   "detail" => "La sesión ya está iniciada.",
18
  ]);
19
20
 return [$san, $rolIds, $usuId];
21
}
22

G. php / ROL_IDS.php

1
<?php
2
3
const ROL_IDS = "rolIds";

H. php / ROL_ID_ADMINISTRADOR.php

1
<?php
2
3
const ROL_ID_ADMINISTRADOR = "Administrador";
4

I. php / ROL_ID_CLIENTE.php

1
<?php
2
3
const ROL_ID_CLIENTE = "Cliente";

J. php / saludo-cliente.php

1
<?php
2
3
require_once __DIR__ . "/lib/manejaErrores.php";
4
require_once __DIR__ . "/lib/devuelveJson.php";
5
require_once __DIR__ . "/ROL_ID_CLIENTE.php";
6
require_once __DIR__ . "/protege.php";
7
8
list($san) = protege([ROL_ID_CLIENTE]);
9
10
devuelveJson("Hola " . $san);
11

K. php / SAN.php

1
<?php
2
3
const SAN = "san";

L. php / usuarioBuscaSan.php

1
<?php
2
3
function usuarioBuscaSan(\PDO $bd, string $san)
4
{
5
 $usuarioBusca = $bd->prepare("SELECT * FROM USUARIO WHERE USU_SAN = :USU_SAN");
6
 $usuarioBusca->execute([":USU_SAN" => $san]);
7
 $usuario = $usuarioBusca->fetch(PDO::FETCH_ASSOC);
8
 return $usuario;
9
}
10

M. php / USU_ID.php

1
<?php
2
3
const USU_ID = "USU_ID";

N. php / vista-administrador.php

1
<?php
2
3
require_once __DIR__ . "/lib/manejaErrores.php";
4
require_once __DIR__ . "/protege.php";
5
require_once __DIR__ . "/lib/devuelveJson.php";
6
require_once __DIR__ . "/ROL_ID_ADMINISTRADOR.php";
7
require_once __DIR__ . "/jsonMiNav.php";
8
9
list($san, $rolIds) = protege([ROL_ID_ADMINISTRADOR]);
10
devuelveJson([
11
 ...jsonMiNav($san, $rolIds),
12
 "main" => ["hidden" => false],
13
]);
14

O. php / vista-cliente.php

1
<?php
2
3
require_once __DIR__ . "/lib/manejaErrores.php";
4
require_once __DIR__ . "/protege.php";
5
require_once __DIR__ . "/lib/devuelveJson.php";
6
require_once __DIR__ . "/ROL_ID_CLIENTE.php";
7
require_once __DIR__ . "/jsonMiNav.php";
8
9
list($san, $rolIds) = protege([ROL_ID_CLIENTE]);
10
11
devuelveJson([
12
 ...jsonMiNav($san, $rolIds),
13
 "main" => ["hidden" => false],
14
]);
15

P. php / vista-index.php

1
<?php
2
3
require_once __DIR__ . "/lib/manejaErrores.php";
4
require_once __DIR__ . "/protege.php";
5
require_once __DIR__ . "/lib/devuelveJson.php";
6
require_once __DIR__ . "/jsonMiNav.php";
7
8
list($san, $rolIds) = protege([]);
9
10
devuelveJson(jsonMiNav($san, $rolIds));
11

Q. php / vista-login.php

1
<?php
2
3
require_once __DIR__ . "/lib/manejaErrores.php";
4
require_once __DIR__ . "/lib/devuelveJson.php";
5
require_once __DIR__ . "/protegeLogin.php";
6
7
list($san) = protegeLogin([]);
8
9
devuelveJson([
10
 "ocupado" => ["hidden" => true],
11
 "formulario" => ["hidden" =>  false],
12
]);
13

R. php / vista-perfil.php

1
<?php
2
3
require_once __DIR__ . "/lib/manejaErrores.php";
4
require_once __DIR__ . "/protege.php";
5
require_once __DIR__ . "/lib/devuelveJson.php";
6
require_once __DIR__ . "/jsonMiNav.php";
7
8
list($san, $rolIds) = protege([]);
9
10
if ($san === "") {
11
 devuelveJson([
12
  ...jsonMiNav($san, $rolIds),
13
  "login" => ["hidden" => false],
14
  "outputSan" => ["value" => "No has iniciado sesión."],
15
  "outputRoles" => ["value" => ""],
16
 ]);
17
} else {
18
 devuelveJson([
19
  ...jsonMiNav($san, $rolIds),
20
  "botonLogout" => ["hidden" => false],
21
  "outputSan" => ["value" => $san],
22
  "outputRoles" => [
23
   "value" => count($rolIds) === 0
24
    ? "Sin roles."
25
    : implode(", ", $rolIds),
26
  ],
27
 ]);
28
}
29

S. Carpeta « php / lib »

Versión para imprimir.

1. php / lib / BAD_REQUEST.php

1
<?php
2
3
const BAD_REQUEST = 400;
4

2. php / lib / devuelveJson.php

1
<?php
2
3
require_once __DIR__ . "/devuelveResultadoNoJson.php";
4
5
function devuelveJson($resultado)
6
{
7
 $json = json_encode($resultado);
8
 if ($json === false) {
9
  devuelveResultadoNoJson();
10
 } else {
11
  header("Content-Type: application/json; charset=utf-8");
12
  echo $json;
13
 }
14
 exit();
15
}
16

3. php / lib / devuelveNoContent.php

1
<?php
2
3
function devuelveNoContent()
4
{
5
 http_response_code(204);
6
}
7

4. php / lib / devuelveResultadoNoJson.php

1
<?php
2
3
require_once __DIR__ . "/INTERNAL_SERVER_ERROR.php";
4
5
function devuelveResultadoNoJson()
6
{
7
 http_response_code(INTERNAL_SERVER_ERROR);
8
 header("Content-Type: application/problem+json; charset=utf-8");
9
10
 echo '{' .
11
  "status: " . INTERNAL_SERVER_ERROR .
12
  '"title": "El resultado no puede representarse como JSON."' .
13
  '"type": "/errors/resultadonojson.html"' .
14
  '}';
15
}
16

5. php / lib / INTERNAL_SERVER_ERROR.php

1
<?php
2
3
const INTERNAL_SERVER_ERROR = 500;

6. php / lib / manejaErrores.php

1
<?php
2
3
require_once __DIR__ . "/INTERNAL_SERVER_ERROR.php";
4
require_once __DIR__ . "/ProblemDetailsException.php";
5
6
// Hace que se lance una excepción automáticamente cuando se genere un error.
7
set_error_handler(function ($severity, $message, $file, $line) {
8
 throw new ErrorException($message, 0, $severity, $file, $line);
9
});
10
11
// Código cuando una excepción no es atrapada.
12
set_exception_handler(function (Throwable $excepcion) {
13
 if ($excepcion instanceof ProblemDetailsException) {
14
  devuelveProblemDetails($excepcion->problemDetails);
15
 } else {
16
  devuelveProblemDetails([
17
   "status" => INTERNAL_SERVER_ERROR,
18
   "title" => "Error interno del servidor",
19
   "detail" => $excepcion->getMessage(),
20
   "type" => "/errors/errorinterno.html",
21
  ]);
22
 }
23
 exit();
24
});
25
26
function devuelveProblemDetails(array $array)
27
{
28
 $json = json_encode($array);
29
 if ($json === false) {
30
  devuelveResultadoNoJson();
31
 } else {
32
  http_response_code(isset($array["status"]) ? $array["status"] : 500);
33
  header("Content-Type: application/problem+json; charset=utf-8");
34
  echo $json;
35
 }
36
}
37

7. php / lib / NO_AUTORIZADO.php

1
<?php
2
3
const NO_AUTORIZADO = 401;
4

8. php / lib / ProblemDetailsException.php

1
<?php
2
3
require_once __DIR__ . "/INTERNAL_SERVER_ERROR.php";
4
5
/**
6
 * Detalle de los errores devueltos por un servicio.
7
 */
8
class ProblemDetailsException extends Exception
9
{
10
11
 public array $problemDetails;
12
13
 public function __construct(
14
  array $problemDetails,
15
 ) {
16
  
17
  parent::__construct(
18
   isset($problemDetails["detail"])
19
    ? $problemDetails["detail"]
20
    : (isset($problemDetails["title"])
21
     ? $problemDetails["title"]
22
     : "Error"),
23
   $problemDetails["status"]
24
    ? $problemDetails["status"]
25
    : INTERNAL_SERVER_ERROR
26
  );
27
28
  $this->problemDetails = $problemDetails;
29
 }
30
}
31

9. php / lib / recibeTexto.php

1
<?php
2
3
/**
4
 * Devuelve el texto de un parámetro enviado al
5
 * servidor por medio de GET, POST o cookie.
6
 * 
7
 * Si el parámetro no se recibe, devuelve false.
8
 */
9
function recibeTexto(string $parametro): false|string
10
{
11
 /* Si el parámetro está asignado en $_REQUEST,
12
  * devuelve su valor; de lo contrario, devuelve false.
13
  */
14
 $valor = isset($_REQUEST[$parametro])
15
  ? $_REQUEST[$parametro]
16
  : false;
17
 return $valor;
18
}
19

10. php / lib / recibeTextoObligatorio.php

1
<?php
2
3
require_once __DIR__ . "/BAD_REQUEST.php";
4
require_once __DIR__ . "/recibeTexto.php";
5
require_once __DIR__ . "/ProblemDetailsException.php";
6
7
function recibeTextoObligatorio(string $parametro)
8
{
9
 $texto = recibeTexto($parametro);
10
11
 if ($texto === false)
12
  throw new ProblemDetailsException([
13
   "status" => BAD_REQUEST,
14
   "title" => "Falta el valor $parametro.",
15
   "type" => "/errors/faltavalor.html",
16
   "detail" => "La solicitud no tiene el valor de $parametro."
17
  ]);
18
19
 $trimTexto = trim($texto);
20
21
 if ($trimTexto === "")
22
  throw new ProblemDetailsException([
23
   "status" => BAD_REQUEST,
24
   "title" => "Campo $parametro en blanco.",
25
   "type" => "/errors/campoenblanco.html",
26
   "detail" => "Pon texto en el campo $parametro."
27
  ]);
28
29
 return $trimTexto;
30
}
31

11. php / lib / rolAgrega.php

1
<?php
2
3
function rolAgrega(\PDO $bd, string $id, string $descripcion)
4
{
5
 $rolAgrega = $bd->prepare(
6
  "INSERT INTO ROL (
7
     ROL_ID, ROL_DESCRIPCION
8
    ) VALUES (
9
     :ROL_ID, :ROL_DESCRIPCION
10
    )"
11
 );
12
 $rolAgrega->execute([
13
  ":ROL_ID" => $id,
14
  ":ROL_DESCRIPCION" => $descripcion,
15
 ]);
16
}
17

12. php / lib / rolBusca.php

1
<?php
2
3
function rolBusca(\PDO $bd, string $id)
4
{
5
 $rolBusca =  $bd->prepare("SELECT * FROM ROL WHERE ROL_ID = :ROL_ID");
6
 $rolBusca->execute([":ROL_ID" => $id]);
7
 $rol = $rolBusca->fetch(PDO::FETCH_ASSOC);
8
 return $rol;
9
}
10

13. php / lib / rolIdsParaUsuId.php

1
<?php
2
3
function rolIdsParaUsuId(\PDO $bd, int $usuId)
4
{
5
 $stmt = $bd->prepare(
6
  "SELECT ROL_ID
7
   FROM USU_ROL
8
   WHERE USU_ID = :USU_ID
9
   ORDER BY USU_ID"
10
 );
11
 $stmt->execute([":USU_ID" => $usuId]);
12
 $rolIds = $stmt->fetchAll(PDO::FETCH_COLUMN, 0);
13
 return $rolIds;
14
}
15

14. php / lib / usuRolAgrega.php

1
<?php
2
3
function usuRolAgrega(\PDO $bd, string $usuId, array $rolIds)
4
{
5
 $usuRolAgrega = $bd->prepare(
6
  "INSERT INTO USU_ROL (USU_ID, ROL_ID) values (:USU_ID, :ROL_ID)"
7
 );
8
 foreach ($rolIds as $rolId) {
9
  $usuRolAgrega->execute([
10
   ":USU_ID" => $usuId,
11
   ":ROL_ID" => $rolId,
12
  ]);
13
 }
14
}
15