aboutsummaryrefslogtreecommitdiff
path: root/formats/AtomFormat.php
blob: 5f564266ce17629e0c6bca5a55d70848e5f5cf64 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
<?php

/**
 * AtomFormat - RFC 4287: The Atom Syndication Format
 * https://tools.ietf.org/html/rfc4287
 *
 * Validator:
 * https://validator.w3.org/feed/
 */
class AtomFormat extends FormatAbstract
{
    const MIME_TYPE = 'application/atom+xml';

    protected const ATOM_NS = 'http://www.w3.org/2005/Atom';
    protected const MRSS_NS = 'http://search.yahoo.com/mrss/';

    const LIMIT_TITLE = 140;

    public function stringify()
    {
        $urlPrefix = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://';
        $urlHost = (isset($_SERVER['HTTP_HOST'])) ? $_SERVER['HTTP_HOST'] : '';
        $urlPath = (isset($_SERVER['PATH_INFO'])) ? $_SERVER['PATH_INFO'] : '';
        $urlRequest = (isset($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : '';

        $feedUrl = $urlPrefix . $urlHost . $urlRequest;

        $extraInfos = $this->getExtraInfos();
        $uri = !empty($extraInfos['uri']) ? $extraInfos['uri'] : REPOSITORY;

        $document = new DomDocument('1.0', $this->getCharset());
        $document->formatOutput = true;
        $feed = $document->createElementNS(self::ATOM_NS, 'feed');
        $document->appendChild($feed);
        $feed->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:media', self::MRSS_NS);

        $title = $document->createElement('title');
        $feed->appendChild($title);
        $title->setAttribute('type', 'text');
        $title->appendChild($document->createTextNode($extraInfos['name']));

        $id = $document->createElement('id');
        $feed->appendChild($id);
        $id->appendChild($document->createTextNode($feedUrl));

        $uriparts = parse_url($uri);
        if (!empty($extraInfos['icon'])) {
            $iconUrl = $extraInfos['icon'];
        } else {
            $iconUrl = $uriparts['scheme'] . '://' . $uriparts['host'] . '/favicon.ico';
        }
        $icon = $document->createElement('icon');
        $feed->appendChild($icon);
        $icon->appendChild($document->createTextNode($iconUrl));

        $logo = $document->createElement('logo');
        $feed->appendChild($logo);
        $logo->appendChild($document->createTextNode($iconUrl));

        $feedTimestamp = gmdate(DATE_ATOM, $this->lastModified);
        $updated = $document->createElement('updated');
        $feed->appendChild($updated);
        $updated->appendChild($document->createTextNode($feedTimestamp));

        // since we can't guarantee that all items have an author,
        // a global feed author is mandatory
        $feedAuthor = 'RSS-Bridge';
        $author = $document->createElement('author');
        $feed->appendChild($author);
        $authorName = $document->createElement('name');
        $author->appendChild($authorName);
        $authorName->appendChild($document->createTextNode($feedAuthor));

        $linkAlternate = $document->createElement('link');
        $feed->appendChild($linkAlternate);
        $linkAlternate->setAttribute('rel', 'alternate');
        $linkAlternate->setAttribute('type', 'text/html');
        $linkAlternate->setAttribute('href', $uri);

        $linkSelf = $document->createElement('link');
        $feed->appendChild($linkSelf);
        $linkSelf->setAttribute('rel', 'self');
        $linkSelf->setAttribute('type', 'application/atom+xml');
        $linkSelf->setAttribute('href', $feedUrl);

        foreach ($this->getItems() as $item) {
            $entryTimestamp = $item->getTimestamp();
            $entryTitle = $item->getTitle();
            $entryContent = $item->getContent();
            $entryUri = $item->getURI();
            $entryID = '';

            if (!empty($item->getUid())) {
                $entryID = 'urn:sha1:' . $item->getUid();
            }

            if (empty($entryID)) { // Fallback to provided URI
                $entryID = $entryUri;
            }

            if (empty($entryID)) { // Fallback to title and content
                $entryID = 'urn:sha1:' . hash('sha1', $entryTitle . $entryContent);
            }

            if (empty($entryTimestamp)) {
                $entryTimestamp = $this->lastModified;
            }

            if (empty($entryTitle)) {
                $entryTitle = str_replace("\n", ' ', strip_tags($entryContent));
                if (strlen($entryTitle) > self::LIMIT_TITLE) {
                    $wrapPos = strpos(wordwrap($entryTitle, self::LIMIT_TITLE), "\n");
                    $entryTitle = substr($entryTitle, 0, $wrapPos) . '...';
                }
            }

            if (empty($entryContent)) {
                $entryContent = ' ';
            }

            $entry = $document->createElement('entry');
            $feed->appendChild($entry);

            $title = $document->createElement('title');
            $entry->appendChild($title);
            $title->setAttribute('type', 'html');
            $title->appendChild($document->createTextNode($entryTitle));

            $entryTimestamp = gmdate(DATE_ATOM, $entryTimestamp);
            $published = $document->createElement('published');
            $entry->appendChild($published);
            $published->appendChild($document->createTextNode($entryTimestamp));

            $updated = $document->createElement('updated');
            $entry->appendChild($updated);
            $updated->appendChild($document->createTextNode($entryTimestamp));

            $id = $document->createElement('id');
            $entry->appendChild($id);
            $id->appendChild($document->createTextNode($entryID));

            if (!empty($entryUri)) {
                $entryLinkAlternate = $document->createElement('link');
                $entry->appendChild($entryLinkAlternate);
                $entryLinkAlternate->setAttribute('rel', 'alternate');
                $entryLinkAlternate->setAttribute('type', 'text/html');
                $entryLinkAlternate->setAttribute('href', $entryUri);
            }

            if (!empty($item->getAuthor())) {
                $author = $document->createElement('author');
                $entry->appendChild($author);
                $authorName = $document->createElement('name');
                $author->appendChild($authorName);
                $authorName->appendChild($document->createTextNode($item->getAuthor()));
            }

            $content = $document->createElement('content');
            $content->setAttribute('type', 'html');
            $content->appendChild($document->createTextNode($this->sanitizeHtml($entryContent)));
            $entry->appendChild($content);

            foreach ($item->getEnclosures() as $enclosure) {
                $entryEnclosure = $document->createElement('link');
                $entry->appendChild($entryEnclosure);
                $entryEnclosure->setAttribute('rel', 'enclosure');
                $entryEnclosure->setAttribute('type', getMimeType($enclosure));
                $entryEnclosure->setAttribute('href', $enclosure);
            }

            foreach ($item->getCategories() as $category) {
                $entryCategory = $document->createElement('category');
                $entry->appendChild($entryCategory);
                $entryCategory->setAttribute('term', $category);
            }

            if (!empty($item->thumbnail)) {
                $thumbnail = $document->createElementNS(self::MRSS_NS, 'thumbnail');
                $entry->appendChild($thumbnail);
                $thumbnail->setAttribute('url', $item->thumbnail);
            }
        }

        $toReturn = $document->saveXML();

        // Remove invalid characters
        ini_set('mbstring.substitute_character', 'none');
        $toReturn = mb_convert_encoding($toReturn, $this->getCharset(), 'UTF-8');
        return $toReturn;
    }
}