Completed
Push — development ( 1b87d2...43bb99 )
by Thomas
06:02
created

htdocs/util2/cron/modules/geokrety.class.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/***************************************************************************
3
 * for license information see LICENSE.md
4
 *  Import new data from geokrety.org.
5
 *  See util2/geokrety for check and repair functions.
6
 *  See discussion in http://redmine.opencaching.de/issues/18.
7
 ***************************************************************************/
8
9
checkJob(new Geokrety());
10
11
class Geokrety
12
{
13
    public $name = 'geokrety';
14
    public $interval = 900;
15
16
    public function run()
17
    {
18
        global $opt;
19
20
        if ($opt['cron']['geokrety']['run']) {
21
            $xmlfile = $this->loadXML();
22
            if ($xmlfile === false) {
23
                return;
24
            }
25
26
            $this->importXML($xmlfile);
27
            if (!$opt['cron']['geokrety']['xml_archive']) {
28
                $this->removeXML($xmlfile);
29
            }
30
        }
31
    }
32
33
    /* get file from XML interface
34
     * and return path of saved xml
35
     * or false on error
36
     */
37
    public function loadXML()
38
    {
39
        global $opt;
40
41
        if (!@mkdir(__DIR__ . '/../../../var/cache2/geokrety')) {
42
            // die('can\'t create geogrety cache dir');
43
        }
44
        $path = __DIR__ . '/../../../var/cache2/geokrety/import-' . date('Ymd-His') . '.xml';
45
46
        // Changed default-value for getSysConfig() from '2005-01-01 00:00:00' to 'NOW - 9d 12h'
47
        // to safely stay in api-limit, even when client and server are in different time zones.
48
        $modifiedSince = strtotime(
49
            getSysConfig('geokrety_lastupdate', date($opt['db']['dateformat'], time() - 60 * 60 * 24 * 9.5))
50
        );
51
        if (!@copy('https://geokrety.org/export.php?modifiedsince=' . date('YmdHis', $modifiedSince - 1), $path)) {
52
            return false;
53
        }
54
55
        return $path;
56
    }
57
58
    /**
59
     * @param string $file
60
     */
61
    public function removeXML($file)
62
    {
63
        @unlink($file);
64
    }
65
66
    /**
67
     * @param string $file
68
     */
69
    public function importXML($file)
70
    {
71
        global $opt;
72
73
        $xr = new XMLReader();
74
        if (!$xr->open($file)) {
75
            $xr->close();
76
77
            return;
78
        }
79
80
        $xr->read();
81
        if ($xr->nodeType != XMLReader::ELEMENT) {
82
            echo 'error: First element expected, aborted' . "\n";
83
84
            return;
85
        }
86
        if ($xr->name != 'gkxml') {
87
            echo 'error: First element not valid, aborted' . "\n";
88
89
            return;
90
        }
91
92
        $startUpdate = $xr->getAttribute('date');
93
        if ($startUpdate === '') {
94
            echo 'error: Date attribute not valid, aborted' . "\n";
95
96
            return;
97
        }
98
//      is probably noot needed
99
//        while ($xr->read() && !($xr->name == 'geokret' || $xr->name == 'moves')) {}
100
101
        $nRecordsCount = 0;
102
        do {
103
            if ($xr->nodeType == XMLReader::ELEMENT) {
104
                $element = $xr->expand();
105
                switch ($xr->name) {
106
                    case 'geokret':
107
                        $this->importGeoKret($element);
108
                        break;
109
                    case 'moves':
110
                        $this->importMove($element);
111
                        break;
112
                }
113
114
                $nRecordsCount++;
115
            }
116
        } while ($xr->next());
117
118
        $xr->close();
119
120
        setSysConfig('geokrety_lastupdate', date($opt['db']['dateformat'], strtotime($startUpdate)));
121
    }
122
123
    /**
124
     * @param DOMNode $element
125
     */
126
    public function importGeoKret($element)
127
    {
128
        global $opt;
129
130
        $id = $element->getAttribute('id');
131
132
        $name = html_entity_decode($this->getNodeValue($element, 'name'));
133
        if ($name === '') {
134
            return;
135
        }
136
137
        $userId = $this->getNodeAttribute($element, 'owner', 'id') + 0;
138
        $username = $this->getNodeValue($element, 'owner');
139
        $this->checkUser($userId, $username);
140
141
        $typeId = $this->getNodeAttribute($element, 'type', 'id') + 0;
142
        $typename = $this->getNodeValue($element, 'type');
143
        $this->checkGeoKretType($typeId, $typename);
144
145
        $description = html_entity_decode($this->getNodeValue($element, 'description'));
146
        $dateCreated = strtotime($this->getNodeValue($element, 'datecreated'));
147
148
        $distanceTravelled = $this->getNodeValue($element, 'distancetravelled') + 0;
149
        $state = $this->getNodeValue($element, 'state') + 0;
150
151
        $longitude = $this->getNodeAttribute($element, 'position', 'longitude') + 0;
152
        $latitude = $this->getNodeAttribute($element, 'position', 'latitude') + 0;
153
154
        sql(
155
            "INSERT INTO `gk_item`
156
                    (`id`, `name`, `description`, `userid`, `datecreated`,
157
                    `distancetravelled`, `latitude`, `longitude`, `typeid`, `stateid`)
158
            VALUES ('&1', '&2', '&3', '&4', '&5', '&6', '&7', '&8', '&9', '&10')
159
            ON DUPLICATE KEY UPDATE
160
            `name`='&2', `description`='&3', `userid`='&4', `datecreated`='&5', `distancetravelled`='&6',
161
            `latitude`='&7', `longitude`='&8', `typeid`='&9', `stateid`='&10'",
162
            $id,
163
            $name,
164
            $description,
165
            $userId,
166
            date($opt['db']['dateformat'], $dateCreated),
167
            $distanceTravelled,
168
            $latitude,
169
            $longitude,
170
            $typeId,
171
            $state
172
        );
173
174
        // Deleting and inserting item-waypoints if they have not changed will
175
        // update caches.meta_last_modified -> caches.okapi_syncbase and thus trigger
176
        // OKAPI changelog actions. This probably can be ignored as OKAPI will verify
177
        // if data has really changed.
178
179
        // update associated waypoints
180
        /**
181
         * This does not work properly, because geokret.waypoints does NOT contain the
182
         * current location of the Kret but something like the last cache where it was logged.
183
         * Evaluating the 'state' fielt might help, but for now, we import waypoint data
184
         * from the moves instead.
185
         * sql("DELETE FROM `gk_item_waypoint` WHERE id='&1'", $id);
186
         * $waypoints = $element->getElementsByTagName('waypoints');
187
         * if ($waypoints->length > 0)
188
         * {
189
         * $wpItems = $waypoints->item(0)->getElementsByTagName('waypoint');
190
         * for ($i = 0; $i < $wpItems->length; $i++)
191
         * {
192
         * $wp = $wpItems->item($i)->nodeValue;
193
         * if ($wp != '')
194
         * sql("INSERT INTO `gk_item_waypoint`
195
         * (`id`, `wp`)
196
         * VALUES
197
         * ('&1', '&2')",
198
         * $id, $wp);
199
         * }
200
         * }
201
         */
202
    }
203
204
    /**
205
     * @param DOMNode $element
206
     */
207
    public function importMove($element)
208
    {
209
        global $opt;
210
211
        $id = $element->getAttribute('id') + 0;
212
213
        $gkId = $this->getNodeAttribute($element, 'geokret', 'id') + 0;
214
        if (sql_value("SELECT COUNT(*) FROM `gk_item` WHERE `id`='&1'", 0, $gkId) == 0) {
215
            return;
216
        }
217
218
        $latitude = $this->getNodeAttribute($element, 'position', 'latitude') + 0;
219
        $longitude = $this->getNodeAttribute($element, 'position', 'longitude') + 0;
220
221
        $dateLogged = strtotime($this->getNodeAttribute($element, 'date', 'logged'));
222
        $dateMoved = strtotime($this->getNodeAttribute($element, 'date', 'moved'));
223
        $userId = $this->getNodeAttribute($element, 'user', 'id') + 0;
224
        $username = $this->getNodeValue($element, 'user');
225
        $this->checkUser($userId, $username);
226
227
        $comment = html_entity_decode($this->getNodeValue($element, 'comment'));
228
        $logTypeId = $this->getNodeAttribute($element, 'logtype', 'id') + 0;
229
        $logTypeName = $this->getNodeValue($element, 'logtype');
230
        $this->checkMoveType($logTypeId, $logTypeName);
231
232
        sql(
233
            "INSERT INTO `gk_move`
234
                (`id`, `itemid`, `latitude`, `longitude`, `datemoved`, `datelogged`, `userid`, `comment`, `logtypeid`)
235
            VALUES ('&1', '&2', '&3', '&4', '&5', '&6', '&7', '&8', '&9')
236
            ON DUPLICATE KEY UPDATE
237
                `itemid`='&2', `latitude`='&3', `longitude`='&4', `datemoved`='&5',
238
                `datelogged`='&6', `userid`='&7', `comment`='&8', `logtypeid`='&9'",
239
            $id,
240
            $gkId,
241
            $latitude,
242
            $longitude,
243
            date($opt['db']['dateformat'], $dateMoved),
244
            date($opt['db']['dateformat'], $dateLogged),
245
            $userId,
246
            $comment,
247
            $logTypeId
248
        );
249
250
        sql("DELETE FROM `gk_move_waypoint` WHERE id='&1'", $id);
251
252
        // update associated waypoints
253
        $waypoints = $element->getElementsByTagName('waypoints');
254
        if ($waypoints->length > 0) {
255
            $wpItems = $waypoints->item(0)->getElementsByTagName('waypoint');
256
            for ($i = 0; $i < $wpItems->length; $i++) {
257
                $wp = mb_trim($wpItems->item($i)->nodeValue);
258
                if ($wp != '') {
259
                    sql("INSERT INTO `gk_move_waypoint` (`id`, `wp`) VALUES ('&1', '&2')", $id, $wp);
260
                }
261
            }
262
        }
263
264
        // update the current gk-waypoints based on the last move
265
        sql("DELETE FROM `gk_item_waypoint` WHERE `id`='&1'", $gkId);
266
        $rs = sql(
267
            "
268
                SELECT `id`,`logtypeid` FROM `gk_move`
269
                WHERE `itemid`='&1' AND `logtypeid`!=2
270
                ORDER BY `datemoved` DESC LIMIT 1",
271
            $gkId
272
        );
273
        $r = sql_fetch_assoc($rs);
274
        sql_free_result($rs);
275
        if ($r === false) {
276
            return;
277
        }
278
279
        if ($r['logtypeid'] == 0 /* dropped */ || $r['logtypeid'] == 3 /* seen in */) {
280
            sql(
281
                "
282
                INSERT INTO `gk_item_waypoint` (`id`, `wp`)
283
                SELECT '&1' AS `id`, `wp`
284
                FROM `gk_move_waypoint`
285
                WHERE `id`='&2' AND `wp`!=''",
286
                $gkId,
287
                $r['id']
288
            ); // "late log" bugfix: replaced $id parameter by $r['id']
289
        }
290
    }
291
292
    /**
293
     * @param int $id
294
     * @param $name
295
     */
296
    public function checkGeoKretType($id, $name)
297
    {
298
        sql(
299
            "INSERT INTO `gk_item_type` (`id`, `name`) VALUES ('&1', '&2') ON DUPLICATE KEY UPDATE `name`='&2'",
300
            $id,
301
            $name
302
        );
303
    }
304
305
    /**
306
     * @param int $id
307
     * @param $name
308
     */
309
    public function checkUser($id, $name)
310
    {
311
        if ($id === 0) {
312
            return;
313
        }
314
315
        sql("INSERT INTO `gk_user` (`id`, `name`) VALUES ('&1', '&2') ON DUPLICATE KEY UPDATE `name`='&2'", $id, $name);
316
    }
317
318
    /**
319
     * @param int $id
320
     * @param $name
321
     */
322
    public function checkMoveType($id, $name)
323
    {
324
        sql(
325
            "INSERT INTO `gk_move_type` (`id`, `name`) VALUES ('&1', '&2') ON DUPLICATE KEY UPDATE `name`='&2'",
326
            $id,
327
            $name
328
        );
329
    }
330
331
    /**
332
     * @param $domNode
333
     * @param string $element
334
     * @return string
335
     */
336 View Code Duplication
    public function getNodeValue(&$domNode, $element)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
337
    {
338
        $subNode = $domNode->getElementsByTagName($element);
339
        if ($subNode->length < 1) {
340
            return '';
341
        }
342
343
        return $subNode->item(0)->nodeValue;
344
    }
345
346
    /**
347
     * @param string $element
348
     * @param string $attr
349
     * @param & $domNode
0 ignored issues
show
The doc-type & could not be parsed: Unknown type name "&" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
350
     * @return string
351
     */
352 View Code Duplication
    public function getNodeAttribute(&$domNode, $element, $attr)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
353
    {
354
        $subNode = $domNode->getElementsByTagName($element);
355
        if ($subNode->length < 1) {
356
            return '';
357
        }
358
359
        return $subNode->item(0)->getAttribute($attr);
360
    }
361
}
362