fix bookmarklet on firefox
[stapibas.git] / src / stapibas / Feed / UpdateFeeds.php
1 <?php
2 namespace stapibas;
3
4 /**
5  * Fetches feeds that need an update and updates their feedentries.
6  */
7 class Feed_UpdateFeeds
8 {
9     public $db;
10     public $log;
11
12     public function __construct(Dependencies $deps)
13     {
14         $this->deps = $deps;
15         $this->db   = $deps->db;
16         $this->log  = $deps->log;
17     }
18
19     public function updateAll()
20     {
21         $this->log->info('Updating feeds..');
22         $res = $this->db->query(
23             'SELECT * FROM feeds'
24             . ' WHERE ' . $this->sqlNeedsUpdate()
25         );
26         while ($feedRow = $res->fetch(\PDO::FETCH_OBJ)) {
27             $this->updateFeed($feedRow);
28         }
29         $this->log->info('Finished updating feeds.');
30     }
31
32     public function updateSome($urlOrIds)
33     {
34         $options = array();
35         foreach ($urlOrIds as $urlOrId) {
36             if (is_numeric($urlOrId)) {
37                 $options[] = 'f_id = ' . intval($urlOrId);
38             } else {
39                 $options[] = 'f_url = ' . $this->db->quote($urlOrId);
40             }
41         }
42
43         $this->log->info('Updating %d feeds..', $options);
44         $res = $this->db->query(
45             'SELECT * FROM feeds'
46             . ' WHERE'
47             . $this->sqlNeedsUpdate()
48             . ' AND (' . implode(' OR ', $options) . ')'
49         );
50
51         $items = 0;
52         while ($feedRow = $res->fetch(\PDO::FETCH_OBJ)) {
53             ++$items;
54             $this->updateFeed($feedRow);
55         }
56         $this->log->info('Finished updating %d feeds.', $items);
57     }
58
59     protected function updateFeed($feedRow)
60     {
61         $this->log->info(
62             'Updating feed #%d: %s', $feedRow->f_id, $feedRow->f_url
63         );
64
65         $req = new \HTTP_Request2($feedRow->f_url);
66         $req->setHeader('User-Agent', 'stapibas');
67
68         if ($feedRow->f_updated != '0000-00-00 00:00:00') {
69             $req->setHeader(
70                 'If-Modified-Since',
71                 gmdate('r', strtotime($feedRow->f_updated))
72             );
73         }
74
75         $res = $req->send();
76         if ($res->getStatus() == 304) {
77             //not modified
78             $this->setNoUpdate($feedRow);
79             $this->log->info('Not modified');
80             return;
81         }
82
83         if (intval($res->getStatus() / 100) != 2) {
84             //no 2xx is an error for us
85             $this->log->err('Error fetching feed');
86             return;
87         }
88
89         $this->updateEntries($feedRow, $res);
90     }
91
92     protected function updateEntries($feedRow, \HTTP_Request2_Response $res)
93     {
94         require_once $GLOBALS['stapibas_libdir'] . '/simplepie/autoloader.php';
95         $sp = new \SimplePie();
96         $sp->set_raw_data($res->getBody());
97         $sp->init();
98
99         $new = $updated = $items = 0;
100         foreach ($sp->get_items() as $item) {
101             ++$items;
102             $url = $item->get_permalink();
103             $entryRow = $this->db->query(
104                 'SELECT fe_id, fe_updated, fe_needs_update FROM feedentries'
105                 . ' WHERE fe_url = ' . $this->db->quote($url)
106                 . ' AND fe_f_id = ' . $this->db->quote($feedRow->f_id)
107             )->fetch(\PDO::FETCH_OBJ);
108
109             if ($entryRow === false) {
110                 //new item!
111                 $this->db->exec(
112                     'INSERT INTO feedentries SET'
113                     . '  fe_f_id = ' . $this->db->quote($feedRow->f_id)
114                     . ', fe_url = ' . $this->db->quote($url)
115                     . ', fe_needs_update = 1'
116                 );
117                 ++$new;
118                 continue;
119             }
120             if ($entryRow->fe_needs_update == 0
121                 && $item->get_updated_gmdate('U') > strtotime($entryRow->fe_updated)
122             ) {
123                 //updated
124                 $this->db->exec(
125                     'UPDATE feedentries SET'
126                     . '  fe_url = ' . $this->db->quote($url)
127                     . ', fe_needs_update = 1'
128                     . ' WHERE fe_id = ' . $this->db->quote($entryRow->fe_id)
129                 );
130                 ++$updated;
131                 continue;
132             }
133         }
134         $this->log->info(
135             'Feed #%d: %d new, %d updated of %d entries',
136             $feedRow->f_id, $new, $updated, $items
137         );
138         $this->setUpdated($feedRow, $res);
139     }
140
141     protected function setNoUpdate($feedRow)
142     {
143         $this->db->exec(
144             'UPDATE feeds SET f_needs_update = 0'
145             . ' WHERE f_id = ' . $this->db->quote($feedRow->f_id)
146         );
147     }
148
149     protected function setUpdated($feedRow, \HTTP_Request2_Response $res)
150     {
151         $this->db->exec(
152             'UPDATE feeds'
153             . ' SET f_needs_update = 0'
154             . ', f_updated = ' . $this->db->quote(
155                 gmdate('Y-m-d H:i:s', strtotime($res->getHeader('last-modified')))
156             )
157             . ' WHERE f_id = ' . $this->db->quote($feedRow->f_id)
158         );
159     }
160
161     protected function sqlNeedsUpdate()
162     {
163         if ($this->deps->options['force']) {
164             return ' 1';
165         }
166         return ' (f_needs_update = 1 OR f_updated = "0000-00-00 00:00:00")';
167     }
168 }
169 ?>