5aac9b25d1200d7b99c4cf0b371f7474b29f8f97
[phinde.git] / src / phinde / Subscriptions.php
1 <?php
2 namespace phinde;
3
4 /**
5  * Database table containing information about Pubsubhubbub subscriptions
6  */
7 class Subscriptions
8 {
9     protected $db;
10
11     public function __construct()
12     {
13         $this->db = new \PDO(
14             $GLOBALS['phinde']['db_dsn'],
15             $GLOBALS['phinde']['db_user'],
16             $GLOBALS['phinde']['db_pass']
17         );
18         $this->db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); 
19     }
20
21     /**
22      * Fetch a topic
23      *
24      * @param string $topic Topic URL
25      *
26      * @return false|object False if the row does not exist
27      */
28     public function get($topic)
29     {
30         $stmt = $this->db->prepare(
31             'SELECT * FROM subscriptions'
32             . ' WHERE sub_topic = :topic'
33         );
34         $stmt->execute([':topic' => $topic]);
35
36         //fetchObject() itself returns FALSE on failure
37         return $stmt->fetchObject();
38     }
39
40     /**
41      * Count number of subscriptions
42      *
43      * @return array Array of keys with different status, number as value
44      */
45     public function count()
46     {
47         $stmt = $this->db->prepare(
48             'SELECT COUNT(*) as count, sub_status FROM subscriptions'
49             . ' GROUP BY sub_status'
50             . ' ORDER BY sub_status'
51         );
52         $stmt->execute();
53
54         $res = [];
55         foreach ($stmt as $row) {
56             $res[$row['sub_status']] = $row['count'];
57         }
58
59         return $res;
60     }
61
62     /**
63      * Create a new subscription entry in database.
64      * Automatically generates secret, capkey and lease seconds.
65      *
66      * This method does NOT:
67      * - check for duplicates (do it yourself)
68      * - return the object (fetch it yourself)
69      * - send subscription requests to the hub
70      *
71      * @param string $topic URL to subscribe to
72      *
73      * @return void
74      */
75     public function create($topic)
76     {
77         $stmt = $this->db->prepare(
78             'INSERT INTO subscriptions'
79             . ' (sub_topic, sub_status, sub_lease_seconds, sub_expires'
80             . ', sub_secret, sub_capkey, sub_created, sub_updated'
81             . ', sub_pings, sub_lastping, sub_statusmessage)'
82             . ' VALUES '
83             . ' (:topic, "subscribing", :lease_seconds, "0000-00-00 00:00:00"'
84             . ', :secret, :capkey, NOW(), NOW()'
85             . ', 0, "0000-00-00 00:00:00", "")'
86         );
87         $stmt->execute(
88             [
89                 ':topic'         => $topic,
90                 ':lease_seconds' => 86400 * 30,
91                 ':secret'        => bin2hex(openssl_random_pseudo_bytes(16)),
92                 ':capkey'        => bin2hex(openssl_random_pseudo_bytes(16)),
93             ]
94         );
95     }
96
97     /**
98      * A subscription has been confirmed by the hub - mark it as active.
99      *
100      * @param integer $subId        Subscription ID
101      * @param integer $leaseSeconds Number of seconds until subscription expires
102      *
103      * @return void
104      */
105     public function subscribed($subId, $leaseSeconds)
106     {
107         $this->db->prepare(
108             'UPDATE subscriptions'
109             . ' SET sub_status        = "active"'
110             . '   , sub_lease_seconds = :leaseSeconds'
111             . '   , sub_expires       = :expires'
112             . '   , sub_updated       = NOW()'
113             . ' WHERE sub_id = :id'
114         )->execute(
115             [
116                 ':leaseSeconds' => $leaseSeconds,
117                 ':expires' => gmdate('Y-m-d H:i:s', time() + $leaseSeconds),
118                 ':id' => $subId,
119             ]
120         );
121     }
122
123     /**
124      * Mark a subscription as "unsubscribed"
125      *
126      * @param integer $subId Subscription ID
127      *
128      * @return void
129      */
130     public function unsubscribed($subId)
131     {
132         $this->db->prepare(
133             'UPDATE subscriptions'
134             . ' SET sub_status = "unsubscribed"'
135             . '   , sub_updated = NOW()'
136             . ' WHERE sub_id = :id'
137         )->execute([':id' => $subId]);
138     }
139
140     public function denied($subId, $reason)
141     {
142         $this->db->prepare(
143             'UPDATE subscriptions'
144             . ' SET sub_status = "denied"'
145             . '   , sub_statusmessage = :reason'
146             . '   , sub_updated = NOW()'
147             . ' WHERE sub_id = :id'
148         )->execute([':id' => $subId, ':reason' => $reason]);
149     }
150
151     public function pinged($subId)
152     {
153         $this->db->prepare(
154             'UPDATE subscriptions'
155             . ' SET sub_pings    = sub_pings + 1'
156             . '   , sub_lastping = NOW()'
157             . '   , sub_updated  = NOW()'
158             . ' WHERE sub_id = :id'
159         )->execute([':id' => $subId]);
160     }
161
162     /**
163      * Detect the hub for the given topic URL
164      *
165      * @param string $url Topic URL
166      *
167      * @return array Topic URL and hub URL. Hub URL is NULL if there is none.
168      */
169     public function detectHub($url)
170     {
171         $hue = new HubUrlExtractor();
172         $hue->setRequestTemplate(new HttpRequest());
173         $urls = $hue->getUrls($url);
174         //we violate the spec by not requiring a self URL
175         $topicUrl = isset($urls['self']) ? $urls['self'] : $url;
176         $hubUrl   = isset($urls['hub'])  ? $urls['hub'] : null;
177
178         return array($topicUrl, $hubUrl);
179     }
180 }
181 ?>