Passed
Push — master ( dfe250...f7a069 )
by Goffy
04:12
created

ExportICS   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 342
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 214
c 1
b 0
f 1
dl 0
loc 342
rs 10
wmc 16

8 Methods

Rating   Name   Duplication   Size   Complexity  
A cleanUpText() 0 16 1
A createIcsHeader() 0 35 2
A createIcsFooter() 0 3 1
A setEvents() 0 2 1
A createIcsEvent() 0 37 5
A downloadAsIcs() 0 27 4
A __construct() 0 2 1
B setTimeZone() 0 155 1
1
<?php declare(strict_types=1);
2
3
namespace XoopsModules\Wgevents\Export\Ics;
4
5
/*
6
 You may not change or alter any portion of this comment or credits
7
 of supporting developers from this source code or any supporting source code
8
 which is considered copyrighted (c) material of the original comment or credit authors.
9
10
 This program is distributed in the hope that it will be useful,
11
 but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
*/
14
15
/**
16
 * ICS export for XOOPS
17
 *
18
 * @copyright    2021 XOOPS Project (https://xoops.org)
19
 * @license      GPL 2.0 or later
20
 * @package      wgevents
21
 * @author       Goffy - Wedega - Email:[email protected] - Website:https://xoops.wedega.com
22
 */
23
24
25
/**
26
 * Class Object Handler ICS
27
 */
28
class ExportICS {
29
30
    /**
31
     * @var XoopsObject
0 ignored issues
show
Bug introduced by
The type XoopsModules\Wgevents\Export\Ics\XoopsObject was not found. Did you mean XoopsObject? If so, make sure to prefix the type with \.
Loading history...
32
     */
33
    private $events = null;
34
35
    /**
36
     * @var array
37
     */
38
    private $timezone = [];
39
40
    /**
41
     * Constructor
42
     *
43
     */
44
    public function __construct()
45
    {
46
    }
47
48
    /**
49
     * @param $eventsAll
50
     * @return void
51
     */
52
    public function setEvents ($eventsAll) {
53
        $this->events = $eventsAll;
54
    }
55
56
    /**
57
     * download ics file based on given name and content
58
     * @param $filename
59
     * @param $filecontent
60
     * @return bool
61
     */
62
    public function downloadAsIcs($filename, $filecontent ) {
63
        $fileres = \fopen('php://memory','wb');
64
        if (!$fileres) {
0 ignored issues
show
introduced by
$fileres is of type resource, thus it always evaluated to false.
Loading history...
65
            return false;
66
        }
67
68
        if (!\fwrite($fileres, $filecontent)) {
69
            \fclose($fileres);
70
            return false;
71
        }
72
73
        $filesize = \ftell($fileres);
74
75
        \header ( 'Content-Type: text/calendar' );
76
        \header ( 'Content-Disposition: attachment; filename="' . $filename . '"' );
77
        \header('Last-Modified: ' . gmdate('D, d M Y H:i:s \G\M\T' , \time() ));
78
        \header('Content-Length: ' . $filesize);
79
80
        while(\ob_get_level() ) {
81
            \ob_end_clean();
82
        }
83
        \fseek($fileres,0);
84
        \fpassthru( $fileres );
85
86
        \fclose($fileres);
87
88
        return true;
89
    }
90
91
    /**
92
     * function to generate ics file header
93
     * @return false|string
94
     */
95
    public function createIcsHeader () {
96
97
        if (!$this->setTimeZone()) {
98
            echo 'invalid timezone';
99
            return false;
100
        }
101
102
        \date_default_timezone_set($this->timezone['name']);
103
104
        $year            = (int)\date('Y');
105
        $startSummertime = \date_format(\date_create('last Sunday of March '.$year.' 02:00'), 'Ymd') . 'T020000';
106
        $endSummertime   = \date_format(\date_create('last Sunday of October '.$year.' 03:00'), 'Ymd') . 'T030000';
107
108
        $headerLine = 'BEGIN:VCALENDAR' . PHP_EOL;
109
        $headerLine .= 'PRODID:wedega.com' . PHP_EOL;
110
        $headerLine .= 'VERSION:1.0' . PHP_EOL;
111
        $headerLine .= 'METHOD:PUBLISH' . PHP_EOL;
112
        $headerLine .= 'X-MS-OLK-FORCEINSPECTOROPEN:TRUE' . PHP_EOL;
113
        $headerLine .= 'BEGIN:VTIMEZONE' . PHP_EOL;
114
        $headerLine .= 'TZID:' . $this->timezone['name'] . PHP_EOL;
115
        $headerLine .= 'BEGIN:STANDARD' . PHP_EOL;
116
        $headerLine .= 'DTSTART:' . $endSummertime . PHP_EOL;
117
        $headerLine .= 'RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10' . PHP_EOL;
118
        $headerLine .= 'TZOFFSETFROM:' . $this->timezone['standard']['tzoffsetfrom'] . PHP_EOL;
119
        $headerLine .= 'TZOFFSETTO:' . $this->timezone['standard']['tzoffsetto'] . PHP_EOL;
120
        $headerLine .= 'END:STANDARD' . PHP_EOL;
121
        $headerLine .= 'BEGIN:DAYLIGHT' . PHP_EOL;
122
        $headerLine .= 'DTSTART:' . $startSummertime . PHP_EOL;
123
        $headerLine .= 'RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3' . PHP_EOL;
124
        $headerLine .= 'TZOFFSETFROM:' . $this->timezone['daylight']['tzoffsetfrom'] . PHP_EOL;
125
        $headerLine .= 'TZOFFSETTO:' . $this->timezone['daylight']['tzoffsetto'] . PHP_EOL;
126
        $headerLine .= 'END:DAYLIGHT' . PHP_EOL;
127
        $headerLine .= 'END:VTIMEZONE' . PHP_EOL;
128
129
        return $headerLine;
130
    }
131
132
133
    /**
134
     * function to generate ics events
135
     * @return string
136
     */
137
    public function createIcsEvent() {
138
139
        $eventLine = '';
140
        foreach ($this->events as $event) {
141
            $eventLine .= 'BEGIN:VEVENT' . PHP_EOL;
142
            $eventLine .= 'CLASS:PUBLIC' . PHP_EOL;
143
            $eventLine .= 'CREATED:' . \date('Ymd\THis\Z', $event->getVar('datecreated')) . PHP_EOL;
144
            $eventLine .= 'DTEND;TZID="' . $this->timezone['name'] . '":' . \date('Ymd\THis', $event->getVar('dateto')) . PHP_EOL;
145
            $eventLine .= 'DTSTAMP:20220912T091145Z' . PHP_EOL;
146
            $eventLine .= 'DTSTART;TZID="' . $this->timezone['name'] . '":' . \date('Ymd\THis', $event->getVar('datefrom')) . PHP_EOL;
147
            //$eventLine .= 'LAST-MODIFIED:20220912T091145Z' . PHP_EOL;
148
            $eventLine .= 'LAST-MODIFIED:' . \date('Ymd\THis\Z', $event->getVar('datecreated')) . PHP_EOL;
149
            $evLocation = $event->getVar('location');
150
            if (\strlen($evLocation) > 0) {
151
                $eventLine .= 'LOCATION:' . $this->cleanUpText($evLocation) . PHP_EOL;
152
            }
153
            $eventLine .= 'PRIORITY:5' . PHP_EOL;
154
            $eventLine .= 'SEQUENCE:0' . PHP_EOL;
155
            $evName = $event->getVar('name');
156
            if (\strlen($evName) > 0) {
157
                $eventLine .= 'SUMMARY;LANGUAGE=de-at:' . $this->cleanUpText($evName) . PHP_EOL;
158
            }
159
            $evDesc = $event->getVar('desc');
160
            if (\strlen($evDesc) > 0) {
161
                $eventLine .= 'DESCRIPTION;LANGUAGE=de-at:' . $this->cleanUpText($evDesc) . PHP_EOL;
162
            }
163
            $eventLine .= 'TRANSP:OPAQUE' . PHP_EOL;
164
            $eventLine .= 'X-MICROSOFT-CDO-BUSYSTATUS:BUSY' . PHP_EOL;
165
            $eventLine .= 'X-MICROSOFT-CDO-IMPORTANCE:1' . PHP_EOL;
166
            $eventLine .= 'X-MICROSOFT-DISALLOW-COUNTER:FALSE' . PHP_EOL;
167
            $eventLine .= 'X-MS-OLK-AUTOFILLLOCATION:FALSE' . PHP_EOL;
168
            $eventLine .= 'X-MS-OLK-AUTOSTARTCHECK:FALSE' . PHP_EOL;
169
            $eventLine .= 'X-MS-OLK-CONFTYPE:0' . PHP_EOL;
170
            $eventLine .= 'END:VEVENT' . PHP_EOL;
171
        }
172
        
173
        return $eventLine;
174
175
    }
176
177
    /**
178
     * function to generate ics file footer
179
     * @return string
180
     */
181
    public function createIcsFooter () {
182
183
        return 'END:VCALENDAR';
184
185
    }
186
187
    /**
188
     * function to get timezone name and timezone offset depending on $GLOBALS['xoopsConfig']['server_TZ']
189
     * @return bool
190
     */
191
    private function setTimeZone () {
192
193
        $timezoneList = [];
194
        $timezoneList['-12'] = [
195
            'name' => 'Pacific/Kwajalein',
196
            'standard' => ['tzoffsetfrom' => '-1200', 'tzoffsetto' => '-1300'],
197
            'daylight' => ['tzoffsetfrom' => '-1300', 'tzoffsetto' => '-1200']
198
        ];
199
        $timezoneList['-11'] = [
200
            'name' => 'Pacific/Pago_Pago',
201
            'standard' => ['tzoffsetfrom' => '-1100', 'tzoffsetto' => '-1200'],
202
            'daylight' => ['tzoffsetfrom' => '-1200', 'tzoffsetto' => '-1100']
203
        ];
204
        $timezoneList['-10'] = [
205
            'name' => 'Pacific/Honolulu',
206
            'standard' => ['tzoffsetfrom' => '-1000', 'tzoffsetto' => '-1100'],
207
            'daylight' => ['tzoffsetfrom' => '-1100', 'tzoffsetto' => '-1000']
208
        ];
209
        $timezoneList['-9'] = [
210
            'name' => 'America/Anchorage',
211
            'standard' => ['tzoffsetfrom' => '-0900', 'tzoffsetto' => '-1000'],
212
            'daylight' => ['tzoffsetfrom' => '-1000', 'tzoffsetto' => '-0900']
213
        ];
214
        $timezoneList['-8'] = [
215
            'name' => 'America/Los_Angeles',
216
            'standard' => ['tzoffsetfrom' => '-0800', 'tzoffsetto' => '-0900'],
217
            'daylight' => ['tzoffsetfrom' => '-0900', 'tzoffsetto' => '-0800']
218
        ];
219
        $timezoneList['-7'] = [
220
            'name' => 'America/Denver',
221
            'standard' => ['tzoffsetfrom' => '-0700', 'tzoffsetto' => '-0800'],
222
            'daylight' => ['tzoffsetfrom' => '-0800', 'tzoffsetto' => '-0700']
223
        ];
224
        $timezoneList['-6'] = [
225
            'name' => 'America/Mexico_City',
226
            'standard' => ['tzoffsetfrom' => '-0600', 'tzoffsetto' => '-0700'],
227
            'daylight' => ['tzoffsetfrom' => '-0700', 'tzoffsetto' => '-0600']
228
        ];
229
        $timezoneList['-5'] = [
230
            'name' => 'America/New_York',
231
            'standard' => ['tzoffsetfrom' => '-0500', 'tzoffsetto' => '-0600'],
232
            'daylight' => ['tzoffsetfrom' => '-0600', 'tzoffsetto' => '-0500']
233
        ];
234
        $timezoneList['-4'] = [
235
            'name' => 'America/Caracas',
236
            'standard' => ['tzoffsetfrom' => '-0400', 'tzoffsetto' => '-0500'],
237
            'daylight' => ['tzoffsetfrom' => '-0500', 'tzoffsetto' => '-0400']
238
        ];
239
        $timezoneList['-3.5'] = [
240
            'name' => 'America/St_Johns',
241
            'standard' => ['tzoffsetfrom' => '-0300', 'tzoffsetto' => '-0400'],
242
            'daylight' => ['tzoffsetfrom' => '-0400', 'tzoffsetto' => '-0300']
243
        ];
244
        $timezoneList['-3'] = [
245
            'name' => 'America/Buenos_Aires',
246
            'standard' => ['tzoffsetfrom' => '-0200', 'tzoffsetto' => '-0300'],
247
            'daylight' => ['tzoffsetfrom' => '-0300', 'tzoffsetto' => '-0200']
248
        ];
249
        $timezoneList['-2'] = [
250
            'name' => 'Atlantic/South_Georgia',
251
            'standard' => ['tzoffsetfrom' => '-0100', 'tzoffsetto' => '-0200'],
252
            'daylight' => ['tzoffsetfrom' => '-0200', 'tzoffsetto' => '-0100']
253
        ];
254
        $timezoneList['-1'] = [
255
            'name' => 'Atlantic/Azores',
256
            'standard' => ['tzoffsetfrom' => '0000', 'tzoffsetto' => '-0100'],
257
            'daylight' => ['tzoffsetfrom' => '-0100', 'tzoffsetto' => '0000']
258
        ];
259
        $timezoneList['0'] = [
260
            'name' => 'Europe/London',
261
            'standard' => ['tzoffsetfrom' => '+0100', 'tzoffsetto' => '0000'],
262
            'daylight' => ['tzoffsetfrom' => '0000', 'tzoffsetto' => '+0100']
263
        ];
264
        $timezoneList['1'] = [
265
            'name' => 'Europe/Berlin',
266
            'standard' => ['tzoffsetfrom' => '+0200', 'tzoffsetto' => '+0100'],
267
            'daylight' => ['tzoffsetfrom' => '+0100', 'tzoffsetto' => '+0200']];
268
        $timezoneList['2'] = [
269
            'name' => 'Europe/Athens',
270
            'standard' => ['tzoffsetfrom' => '+0300', 'tzoffsetto' => '+0200'],
271
            'daylight' => ['tzoffsetfrom' => '+0200', 'tzoffsetto' => '+0300']
272
        ];
273
        $timezoneList['3'] = [
274
            'name' => 'Europe/Moscow',
275
            'standard' => ['tzoffsetfrom' => '+0400', 'tzoffsetto' => '+0300'],
276
            'daylight' => ['tzoffsetfrom' => '+0300', 'tzoffsetto' => '+0400']
277
        ];
278
        $timezoneList['3.5'] = [
279
            'name' => 'Asia/Tehran',
280
            'standard' => ['tzoffsetfrom' => '+0450', 'tzoffsetto' => '+0350'],
281
            'daylight' => ['tzoffsetfrom' => '+0350', 'tzoffsetto' => '+0450']
282
        ];
283
        $timezoneList['4'] = [
284
            'name' => 'Asia/Baku',
285
            'standard' => ['tzoffsetfrom' => '+0500', 'tzoffsetto' => '+0400'],
286
            'daylight' => ['tzoffsetfrom' => '+0400', 'tzoffsetto' => '+0500']
287
        ];
288
        $timezoneList['4.5'] = [
289
            'name' => 'Asia/Kabul',
290
            'standard' => ['tzoffsetfrom' => '+0550', 'tzoffsetto' => '+0450'],
291
            'daylight' => ['tzoffsetfrom' => '+0450', 'tzoffsetto' => '+0550']
292
        ];
293
        $timezoneList['5'] = [
294
            'name' => 'Asia/Tashkent',
295
            'standard' => ['tzoffsetfrom' => '+0600', 'tzoffsetto' => '+0500'],
296
            'daylight' => ['tzoffsetfrom' => '+0500', 'tzoffsetto' => '+0600']
297
        ];
298
        $timezoneList['5.5'] = [
299
            'name' => 'Asia/Calcutta',
300
            'standard' => ['tzoffsetfrom' => '+0700', 'tzoffsetto' => '+0600'],
301
            'daylight' => ['tzoffsetfrom' => '+0600', 'tzoffsetto' => '+0700']
302
        ];
303
        $timezoneList['6'] = [
304
            'name' => 'Asia/Dhaka',
305
            'standard' => ['tzoffsetfrom' => '+0750', 'tzoffsetto' => '+0650'],
306
            'daylight' => ['tzoffsetfrom' => '+0650', 'tzoffsetto' => '+0750']
307
        ];
308
        $timezoneList['7'] = [
309
            'name' => 'Asia/Bangkok',
310
            'standard' => ['tzoffsetfrom' => '+0800', 'tzoffsetto' => '+0700'],
311
            'daylight' => ['tzoffsetfrom' => '+0700', 'tzoffsetto' => '+0800']
312
        ];
313
        $timezoneList['8'] = [
314
            'name' => 'Asia/Singapore',
315
            'standard' => ['tzoffsetfrom' => '+0900', 'tzoffsetto' => '+0800'],
316
            'daylight' => ['tzoffsetfrom' => '+0800', 'tzoffsetto' => '+0900']
317
        ];
318
        $timezoneList['9'] = [
319
            'name' => 'Asia/Tokyo',
320
            'standard' => ['tzoffsetfrom' => '+1000', 'tzoffsetto' => '+0900'],
321
            'daylight' => ['tzoffsetfrom' => '+0900', 'tzoffsetto' => '+1000']
322
        ];
323
        $timezoneList['9.5'] = [
324
            'name' => 'Australia/Adelaide',
325
            'standard' => ['tzoffsetfrom' => '+1050', 'tzoffsetto' => '+0950'],
326
            'daylight' => ['tzoffsetfrom' => '+0950', 'tzoffsetto' => '+1050']
327
        ];
328
        $timezoneList['10'] = [
329
            'name' => 'Australia/Sydney Australia/Melbourne',
330
            'standard' => ['tzoffsetfrom' => '+1100', 'tzoffsetto' => '+1000'],
331
            'daylight' => ['tzoffsetfrom' => '+1000', 'tzoffsetto' => '+1100']
332
        ];
333
        $timezoneList['11'] = [
334
            'name' => 'Asia/Magadan',
335
            'standard' => ['tzoffsetfrom' => '+1200', 'tzoffsetto' => '+1100'],
336
            'daylight' => ['tzoffsetfrom' => '+1100', 'tzoffsetto' => '+1200']
337
        ];
338
        $timezoneList['12'] = [
339
            'name' => 'Pacific/Fiji',
340
            'standard' => ['tzoffsetfrom' => '+1300', 'tzoffsetto' => '+1200'],
341
            'daylight' => ['tzoffsetfrom' => '+1200', 'tzoffsetto' => '+1300']
342
        ];
343
344
        $this->timezone = $timezoneList[$GLOBALS['xoopsConfig']['server_TZ']];
345
        return true;
346
347
    }
348
349
    /**
350
     * function to clean the given text in order to avoid errors when importing the ics file into a calendar tools like outlook, thunderbird and so on
351
     * @param $text
352
     * @return string
353
     */
354
    private function cleanUpText ($text) {
355
356
        $textclean = \str_replace ( "\\n", "\n", $text );
357
        $textclean = \str_replace ( "\\'", "'", $textclean );
358
        $textclean = \str_replace ( "\\\"", "\"", $textclean );
359
        $textclean = \str_replace ( "'", "\\'", $textclean );
360
        $textclean = \str_replace ( '=0D=0A=', '<br />', $textclean );
361
        $textclean = \str_replace ( '=0D=0A', '', $textclean );
362
        $textclean = \strip_tags($textclean, '<br><p><li>');
363
        $textclean = \preg_replace ('/<[^>]*>/', ' ', $textclean);
364
365
        $textclean = \html_entity_decode($textclean, ENT_QUOTES | ENT_COMPAT , 'UTF-8');
366
        $textclean = \html_entity_decode($textclean, ENT_HTML5, 'UTF-8');
367
        $textclean = \html_entity_decode($textclean);
368
369
        return \htmlspecialchars_decode($textclean);
370
    }
371
}
372