8. Carpeta « srv »

Versión para imprimir.

A. srv / Bd.php

1<?php
2
3class Bd
4{
5
6 private static ?PDO $pdo = null;
7
8 static function pdo(): PDO
9 {
10 if (self::$pdo === null) {
11
12 self::$pdo = new PDO(
13 // cadena de conexión
14 "sqlite:notificacionespush.db",
15 // usuario
16 null,
17 // contraseña
18 null,
19 // Opciones: pdos no persistentes y lanza excepciones.
20 [PDO::ATTR_PERSISTENT => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
21 );
22
23 self::$pdo->exec(
24 'CREATE TABLE IF NOT EXISTS SUSCRIPCION (
25 SUS_ENDPOINT TEXT NOT NULL,
26 SUS_PUB_KEY TEXT NOT NULL,
27 SUS_AUT_TOK TEXT NOT NULL,
28 SUS_CONT_ENCOD TEXT NOT NULL,
29 CONSTRAINT SUS_PK
30 PRIMARY KEY(SUS_ENDPOINT),
31 CONSTRAINT SUS_ENDPNT_NV
32 CHECK(LENGTH(SUS_ENDPOINT) > 0)
33 )'
34 );
35 }
36
37 return self::$pdo;
38 }
39}
40

B. srv / genera-llaves.php

1<!DOCTYPE html>
2<html lang="es">
3
4<head>
5
6 <meta charset="UTF-8">
7 <meta name="viewport" content="width=device-width">
8
9 <title>Llaves VAPID</title>
10
11</head>
12
13<body>
14
15 <h1>Llaves VAPID</h1>
16
17 <pre>
18 <?php
19
20 require __DIR__ . "/../vendor/autoload.php";
21
22 use Minishlink\WebPush\VAPID;
23
24 var_dump(VAPID::createVapidKeys());
25
26 ?>
27 </pre>
28
29</body>
30
31</html>

C. srv / notifica.php

1<?php
2
3require_once __DIR__ . "/../vendor/autoload.php";
4require_once __DIR__ . "/../lib/php/ejecutaServicio.php";
5require_once __DIR__ . "/../lib/php/select.php";
6require_once __DIR__ . "/../lib/php/devuelveJson.php";
7require_once __DIR__ . "/Bd.php";
8require_once __DIR__ . "/TABLA_SUSCRIPCION.php";
9require_once __DIR__ . "/Suscripcion.php";
10require_once __DIR__ . "/suscripcionElimina.php";
11
12use Minishlink\WebPush\WebPush;
13
14const AUTH = [
15 "VAPID" => [
16 "subject" => "https://notificacionesphp.gilbertopachec2.repl.co/",
17 "publicKey" => "BMBlr6YznhYMX3NgcWIDRxZXs0sh7tCv7_YCsWcww0ZCv9WGg-tRCXfMEHTiBPCksSqeve1twlbmVAZFv7GSuj0",
18 "privateKey" => "vplfkITvu0cwHqzK9Kj-DYStbCH_9AhGx9LqMyaeI6w"
19 ]
20];
21
22ejecutaServicio(function () {
23
24 $webPush = new WebPush(AUTH);
25 $mensaje = "Hola! 👋";
26
27 // Envia el mensaje a todas las suscripciones.
28
29 $pdo = Bd::pdo();
30
31 $suscripciones = select(
32 pdo: $pdo,
33 from: SUSCRIPCION,
34 mode: PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE,
35 opcional: Suscripcion::class
36 );
37
38 foreach ($suscripciones as $suscripcion) {
39 $webPush->queueNotification($suscripcion, $mensaje);
40 }
41 $reportes = $webPush->flush();
42
43 // Genera el reporte de envio a cada suscripcion.
44 $reporteDeEnvios = "";
45 foreach ($reportes as $reporte) {
46 $endpoint = $reporte->getRequest()->getUri();
47 $htmlEndpoint = htmlentities($endpoint);
48 if ($reporte->isSuccess()) {
49 // Reporte de éxito.
50 $reporteDeEnvios .= "<dt>$htmlEndpoint</dt><dd>Éxito</dd>";
51 } else {
52 if ($reporte->isSubscriptionExpired()) {
53 suscripcionElimina($pdo, $endpoint);
54 }
55 // Reporte de fallo.
56 $explicacion = htmlentities($reporte->getReason());
57 $reporteDeEnvios .= "<dt>$endpoint</dt><dd>Fallo: $explicacion</dd>";
58 }
59 }
60
61 devuelveJson(["reporte" => ["innerHTML" => $reporteDeEnvios]]);
62});
63

D. srv / suscripcion-elimina.php

1<?php
2
3require_once __DIR__ . "/../lib/php/ejecutaServicio.php";
4require_once __DIR__ . "/../lib/php/recuperaJson.php";
5require_once __DIR__ . "/../lib/php/devuelveNoContent.php";
6require_once __DIR__ . "/Bd.php";
7require_once __DIR__ . "/suscripcionRecupera.php";
8require_once __DIR__ . "/suscripcionElimina.php";
9
10ejecutaServicio(function () {
11
12 $modelo = suscripcionRecupera();
13 suscripcionElimina(Bd::pdo(), $modelo[SUS_ENDPOINT]);
14 devuelveNoContent();
15});
16

E. srv / suscripcion-modifica.php

1<?php
2
3require_once __DIR__ . "/../lib/php/ejecutaServicio.php";
4require_once __DIR__ . "/../lib/php/selectFirst.php";
5require_once __DIR__ . "/../lib/php/insert.php";
6require_once __DIR__ . "/../lib/php/update.php";
7require_once __DIR__ . "/../lib/php/devuelveCreated.php";
8require_once __DIR__ . "/../lib/php/devuelveJson.php";
9require_once __DIR__ . "/Bd.php";
10require_once __DIR__ . "/Suscripcion.php";
11require_once __DIR__ . "/suscripcionRecupera.php";
12
13ejecutaServicio(function () {
14 $modelo = suscripcionRecupera();
15 $pdo = Bd::pdo();
16 if (
17 selectFirst($pdo, SUSCRIPCION, [SUS_ENDPOINT => $modelo[SUS_ENDPOINT]])
18 === false
19 ) {
20 insert(pdo: $pdo, into: SUSCRIPCION, values: $modelo);
21 devuelveCreated("", $modelo);
22 } else {
23 update(
24 pdo: $pdo,
25 table: SUSCRIPCION,
26 set: $modelo,
27 where: [SUS_ENDPOINT => $modelo[SUS_ENDPOINT]]
28 );
29 devuelveJson($modelo);
30 }
31});
32

F. srv / Suscripcion.php

1<?php
2
3require_once __DIR__ . "/../vendor/autoload.php";
4
5use Minishlink\WebPush\SubscriptionInterface;
6
7class Suscripcion implements SubscriptionInterface
8{
9
10 public string $SUS_ENDPOINT;
11 public string $SUS_PUB_KEY;
12 public string $SUS_AUT_TOK;
13 public string $SUS_CONT_ENCOD;
14
15 public function __construct(
16 string $SUS_ENDPOINT = "",
17 string $SUS_PUB_KEY = "",
18 string $SUS_AUT_TOK = "",
19 string $SUS_CONT_ENCOD = ""
20 ) {
21 $this->SUS_ENDPOINT = $SUS_ENDPOINT;
22 $this->SUS_PUB_KEY = $SUS_PUB_KEY;
23 $this->SUS_AUT_TOK = $SUS_AUT_TOK;
24 $this->SUS_CONT_ENCOD = $SUS_CONT_ENCOD;
25 }
26
27 public function getEndpoint(): string
28 {
29 return $this->SUS_ENDPOINT;
30 }
31
32 public function getPublicKey(): ?string
33 {
34 return $this->SUS_PUB_KEY;
35 }
36
37 public function getAuthToken(): ?string
38 {
39 return $this->SUS_AUT_TOK;
40 }
41
42 public function getContentEncoding(): ?string
43 {
44 return $this->SUS_CONT_ENCOD;
45 }
46}
47

G. srv / suscripcionElimina.php

1<?php
2
3require_once __DIR__ . "/../lib/php/delete.php";
4require_once __DIR__ . "/TABLA_SUSCRIPCION.php";
5
6function suscripcionElimina(PDO $pdo, string $endpoint)
7{
8 delete(pdo: $pdo, from: SUSCRIPCION, where: [SUS_ENDPOINT => $endpoint]);
9}
10

H. srv / suscripcionRecupera.php

1<?php
2
3require_once __DIR__ . "/../lib/php/BAD_REQUEST.php";
4require_once __DIR__ . "/../lib/php/recuperaJson.php";
5require_once __DIR__ . "/../lib/php/validaJson.php";
6require_once __DIR__ . "/../lib/php/ProblemDetails.php";
7require_once __DIR__ . "/TABLA_SUSCRIPCION.php";
8
9function suscripcionRecupera()
10{
11
12 $objeto = recuperaJson();
13 $objeto = validaJson($objeto);
14
15 if (!isset($objeto->publicKey) || !is_string($objeto->publicKey))
16 throw new ProblemDetails(
17 type: "/error/publickeyincorrecta.html",
18 status: BAD_REQUEST,
19 title: "La publicKey debe ser texto.",
20 );
21
22 if (!isset($objeto->authToken) || !is_string($objeto->authToken))
23 throw new ProblemDetails(
24 type: "/error/authtokenincorrecto.html",
25 status: BAD_REQUEST,
26 title: "El authToken debe ser texto.",
27 );
28
29 if (!isset($objeto->contentEncoding) || !is_string($objeto->contentEncoding))
30 throw new ProblemDetails(
31 type: "/error/contentencodingincorrecta.html",
32 status: BAD_REQUEST,
33 title: "La contentEncoding debe ser texto.",
34 );
35
36 return [
37 SUS_ENDPOINT => $objeto->endpoint,
38 SUS_PUB_KEY => $objeto->publicKey,
39 SUS_AUT_TOK => $objeto->authToken,
40 SUS_CONT_ENCOD => $objeto->contentEncoding
41 ];
42}
43

I. srv / TABLA_SUSCRIPCION.php

1<?php
2
3const SUSCRIPCION = "SUSCRIPCION";
4const SUS_ENDPOINT = "SUS_ENDPOINT";
5const SUS_PUB_KEY = "SUS_PUB_KEY";
6const SUS_AUT_TOK = "SUS_AUT_TOK";
7const SUS_CONT_ENCOD = "SUS_CONT_ENCOD";
8