~jstys-z/helioviewer.org/client5

« back to all changes in this revision

Viewing changes to src/php/Database/ImgIndex.php

Preparing to merge in my branch

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
<?php
2
 
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
 
/**
4
 
 * ImgIndex Class definition
5
 
 *
6
 
 * PHP version 5
7
 
 *
8
 
 * @category Database
9
 
 * @package  Helioviewer
10
 
 * @author   Jeff Stys <jeff.stys@nasa.gov>
11
 
 * @author   Keith Hughitt <keith.hughitt@nasa.gov>
12
 
 * @author   Patrick Schmiedel <patrick.schmiedel@gmx.net>
13
 
 * @license  http://www.mozilla.org/MPL/MPL-1.1.html Mozilla Public License 1.1
14
 
 * @link     http://launchpad.net/helioviewer.org
15
 
 */
16
 
/**
17
 
 * Provides methods for interacting with a JPEG 2000 archive.
18
 
 *
19
 
 * @category Database
20
 
 * @package  Helioviewer
21
 
 * @author   Jeff Stys <jeff.stys@nasa.gov>
22
 
 * @author   Keith Hughitt <keith.hughitt@nasa.gov>
23
 
 * @author   Patrick Schmiedel <patrick.schmiedel@gmx.net>
24
 
 * @license  http://www.mozilla.org/MPL/MPL-1.1.html Mozilla Public License 1.1
25
 
 * @link     http://launchpad.net/helioviewer.org
26
 
 */
27
 
class Database_ImgIndex {
28
 
 
29
 
    private $_dbConnection;
30
 
 
31
 
    /**
32
 
     * Constructor method
33
 
     *
34
 
     * @return void
35
 
     */
36
 
    public function __construct() {
37
 
        $this->_dbConnection = false;
38
 
    }
39
 
 
40
 
    /**
41
 
     * Create a connection to the database if one has not already been made.
42
 
     *
43
 
     * @return void
44
 
     */
45
 
    private function _dbConnect() {
46
 
        if ( $this->_dbConnection === false ) {
47
 
            include_once HV_ROOT_DIR.'/src/php/Database/DbConnection.php';
48
 
            $this->_dbConnection = new Database_DbConnection();
49
 
        }
50
 
    }
51
 
 
52
 
    /**
53
 
     * Insert a new screenshot into the `screenshots` table.
54
 
     *
55
 
     * @return int Identifier in the `screenshots` table
56
 
     */
57
 
    public function insertScreenshot($date, $imageScale, $roi, $watermark,
58
 
        $layers, $bitmask, $events, $eventsLabels, $scale, $scaleType,
59
 
        $scaleX, $scaleY, $numLayers) {
60
 
 
61
 
        include_once HV_ROOT_DIR.'/src/php/Helper/DateTimeConversions.php';
62
 
 
63
 
        $this->_dbConnect();
64
 
 
65
 
        $sql = sprintf(
66
 
                  "INSERT INTO screenshots "
67
 
                . "SET "
68
 
                .     "id "                . " = NULL, "
69
 
                .     "timestamp "         . " = NULL, "
70
 
                .     "observationDate "   . " ='%s', "
71
 
                .     "imageScale "        . " = %f, "
72
 
                .     "regionOfInterest "  . " = PolygonFromText('%s'), "
73
 
                .     "watermark "         . " = %b, "
74
 
                .     "dataSourceString "  . " ='%s', "
75
 
                .     "dataSourceBitMask " . " = %d, "
76
 
                .     "eventSourceString " . " ='%s', "
77
 
                .     "eventsLabels "      . " = %b, "
78
 
                .     "scale "             . " = %b, "
79
 
                .     "scaleType "         . " ='%s', "
80
 
                .     "scaleX "            . " = %f, "
81
 
                .     "scaleY "            . " = %f, "
82
 
                .     "numLayers "         . " = %d;",
83
 
                $this->_dbConnection->link->real_escape_string(
84
 
                    isoDateToMySQL($date) ),
85
 
                (float)$imageScale,
86
 
                $this->_dbConnection->link->real_escape_string(
87
 
                    $roi ),
88
 
                (bool)$watermark,
89
 
                $this->_dbConnection->link->real_escape_string(
90
 
                    $layers ),
91
 
                bindec($this->_dbConnection->link->real_escape_string(
92
 
                    (binary)$bitmask ) ),
93
 
                $this->_dbConnection->link->real_escape_string(
94
 
                    $events ),
95
 
                (bool)$eventsLabels,
96
 
                (bool)$scale,
97
 
                $this->_dbConnection->link->real_escape_string(
98
 
                    $scaleType ),
99
 
                (float)$scaleX,
100
 
                (float)$scaleY,
101
 
                (int)$numLayers
102
 
               );
103
 
        try {
104
 
            $result = $this->_dbConnection->query($sql);
105
 
        }
106
 
        catch (Exception $e) {
107
 
            return false;
108
 
        }
109
 
 
110
 
        return $this->_dbConnection->getInsertId();
111
 
    }
112
 
 
113
 
    /**
114
 
     * Fetch metadata about a movie from the `movies` table.
115
 
     *
116
 
     * @param  $movieId  int  Identifier in the `movies` table
117
 
     *
118
 
     * @return Array represesenting a row in the `movies` table
119
 
     */
120
 
    public function getMovieInformation($movieId) {
121
 
        $this->_dbConnect();
122
 
 
123
 
        $sql = sprintf(
124
 
                   "SELECT *, AsText(regionOfInterest) AS roi "
125
 
                 . "FROM movies "
126
 
                 . "LEFT JOIN "
127
 
                 .     "movieFormats ON movies.id = movieFormats.movieId "
128
 
                 . "WHERE "
129
 
                 .     "movies.id = %d AND "
130
 
                 .     "movieFormats.format = 'mp4' "
131
 
                 . "LIMIT 1;",
132
 
                 (int)$movieId
133
 
               );
134
 
        try {
135
 
            $result = $this->_dbConnection->query($sql);
136
 
        }
137
 
        catch (Exception $e) {
138
 
            return false;
139
 
        }
140
 
 
141
 
        return $result->fetch_array(MYSQLI_ASSOC);
142
 
    }
143
 
 
144
 
    /**
145
 
     * Update a row in the `movies` table with metadata describing the
146
 
     * generated movie's attributes.
147
 
     *
148
 
     * @return boolean true or false
149
 
     */
150
 
    public function storeMovieProperties($movieId, $startDate, $endDate,
151
 
        $numFrames, $frameRate, $length, $width, $height) {
152
 
 
153
 
        $this->_dbConnect();
154
 
 
155
 
        $sql = sprintf(
156
 
                   "UPDATE movies "
157
 
                 . "SET "
158
 
                 .     "startDate "    . " ='%s', "
159
 
                 .     "endDate "      . " ='%s', "
160
 
                 .     "numFrames "    . " = %d, "
161
 
                 .     "frameRate "    . " = %f, "
162
 
                 .     "movieLength "  . " = %f, "
163
 
                 .     "width "        . " = %d, "
164
 
                 .     "height "       . " = %d "
165
 
                 . "WHERE id "         . " = %d "
166
 
                 . "LIMIT 1;",
167
 
                 $this->_dbConnection->link->real_escape_string(
168
 
                    $startDate),
169
 
                 $this->_dbConnection->link->real_escape_string(
170
 
                    $endDate),
171
 
                 (int)$numFrames,
172
 
                 (float)$frameRate,
173
 
                 (float)$length,
174
 
                 (int)$width,
175
 
                 (int)$height,
176
 
                 (int)$movieId
177
 
               );
178
 
        try {
179
 
            $result = $this->_dbConnection->query($sql);
180
 
        }
181
 
        catch (Exception $e) {
182
 
            return false;
183
 
        }
184
 
 
185
 
        return true;
186
 
    }
187
 
 
188
 
    /**
189
 
     * Update a row in the `movies` table with processesing start and end times
190
 
     *
191
 
     * @param  $movieId  int  Identifier in the `movies` table
192
 
     * @param  $buildTimeStart string  Movie build start time
193
 
     * @param  $buildTimeEnd   string  Movie build end time
194
 
     *
195
 
     * @return Boolean true or false
196
 
     */
197
 
    public function finishedBuildingMovieFrames($movieId, $buildTimeStart,
198
 
        $buildTimeEnd) {
199
 
 
200
 
        $this->_dbConnect();
201
 
 
202
 
        $sql = sprintf(
203
 
                   "UPDATE movies "
204
 
                 . "SET "
205
 
                 .     "buildTimeStart " . " ='%s', "
206
 
                 .     "buildTimeEnd= "  . " ='%s' "
207
 
                 . "WHERE id "           . " = %d "
208
 
                 . "LIMIT 1;",
209
 
                 $this->_dbConnection->link->real_escape_string(
210
 
                    $buildTimeStart),
211
 
                 $this->_dbConnection->link->real_escape_string(
212
 
                    $buildTimeEnd),
213
 
                 (int)$movieId
214
 
               );
215
 
        try {
216
 
            $result = $this->_dbConnection->query($sql);
217
 
        }
218
 
        catch (Exception $e) {
219
 
            return false;
220
 
        }
221
 
 
222
 
        return true;
223
 
    }
224
 
 
225
 
    /**
226
 
     * Mark a movie as "processing" in the `movieFormats` table.
227
 
     *
228
 
     * @param  $movieId  int     Identifier in the `movies` table
229
 
     * @param  $format   string  Movie format being processed
230
 
     *
231
 
     * @return Boolean true or false
232
 
     */
233
 
    public function markMovieAsProcessing($movieId, $format) {
234
 
        $this->_dbConnect();
235
 
 
236
 
        $sql = sprintf(
237
 
                   "UPDATE movieFormats "
238
 
                 . "SET status = 1 "    // 1 = processing
239
 
                 . "WHERE "
240
 
                 .     "movieId " . " = %d AND "
241
 
                 .     "format "  . " ='%s' "
242
 
                 . "LIMIT 1;",
243
 
                 (int)$movieId,
244
 
                 $this->_dbConnection->link->real_escape_string(
245
 
                    $format)
246
 
               );
247
 
        try {
248
 
            $result = $this->_dbConnection->query($sql);
249
 
        }
250
 
        catch (Exception $e) {
251
 
            return false;
252
 
        }
253
 
 
254
 
        return true;
255
 
    }
256
 
 
257
 
    /**
258
 
     * Mark a movie as "finished" in the `movieFormats` table.
259
 
     *
260
 
     * @param  $movieId  int     Identifier in the `movies` table
261
 
     * @param  $format   string  Movie format being processed
262
 
     * @param  $procTime int     Number of seconds it took to encode the movie
263
 
     *
264
 
     * @return Boolean true or false
265
 
     */
266
 
    public function markMovieAsFinished($movieId, $format, $procTime) {
267
 
        $this->_dbConnect();
268
 
 
269
 
        $sql = sprintf(
270
 
                   "UPDATE movieFormats "
271
 
                 . "SET "
272
 
                 .     "status "   . " = 2, "   // 2 = finished
273
 
                 .     "procTime " . " = %d "
274
 
                 . "WHERE "
275
 
                 .     "movieId "  . " = %d AND "
276
 
                 .     "format "   . " ='%s' "
277
 
                 . "LIMIT 1;",
278
 
                 (int)$procTime,
279
 
                 (int)$movieId,
280
 
                 $this->_dbConnection->link->real_escape_string(
281
 
                    $format)
282
 
               );
283
 
        try {
284
 
            $result = $this->_dbConnection->query($sql);
285
 
        }
286
 
        catch (Exception $e) {
287
 
            return false;
288
 
        }
289
 
 
290
 
        return true;
291
 
    }
292
 
 
293
 
    /**
294
 
     * Mark a movie as "invalid" in the `movieFormats` table.
295
 
     *
296
 
     * @param  int  $movieId  Identifier in the `movies` table
297
 
     *
298
 
     * @return Boolean true or false
299
 
     */
300
 
    public function markMovieAsInvalid($movieId) {
301
 
        $this->_dbConnect();
302
 
 
303
 
        $sql = sprintf(
304
 
                   "UPDATE movieFormats "
305
 
                 . "SET "
306
 
                 .     "status "   . " = 3, "   // 3 = invalid
307
 
                 .     "procTime " . " = NULL "
308
 
                 . "WHERE "
309
 
                 .     "movieId "  . " = %d "
310
 
                 . "LIMIT 1;",
311
 
                 (int)$movieId
312
 
               );
313
 
        try {
314
 
            $result = $this->_dbConnection->query($sql);
315
 
        }
316
 
        catch (Exception $e) {
317
 
            return false;
318
 
        }
319
 
 
320
 
        return true;
321
 
    }
322
 
 
323
 
    /**
324
 
     * Fetch metadata about a screenshot from the `screenshots` table.
325
 
     *
326
 
     * @param  int  $screenshotId Identifier in the `screenshots` table
327
 
     *
328
 
     * @return Array represesenting a row in the `screenshots` table
329
 
     */
330
 
    public function getScreenshot($screenshotId) {
331
 
        $this->_dbConnect();
332
 
 
333
 
        $sql = sprintf(
334
 
                   "SELECT * "
335
 
                 . "FROM screenshots "
336
 
                 . "WHERE id = %d "
337
 
                 . "LIMIT 1;",
338
 
                 (int)$screenshotId
339
 
               );
340
 
        try {
341
 
            $result = $this->_dbConnection->query($sql);
342
 
        }
343
 
        catch (Exception $e) {
344
 
            return false;
345
 
        }
346
 
 
347
 
        return $result->fetch_array(MYSQLI_ASSOC);
348
 
    }
349
 
 
350
 
    /**
351
 
     * Fetch metadata about an image from the `data` and `datasources` tables
352
 
     * as well as the XML box of the JP2 image file.  Not for use with
353
 
     * non-image data sources.
354
 
     *
355
 
     * @param  int   $dataId  The image's identifier in the `data` table
356
 
     *
357
 
     * @return array Metadata related to the requested image.
358
 
     */
359
 
    public function getImageInformation($dataId) {
360
 
        $this->_dbConnect();
361
 
 
362
 
        $sql  = sprintf(
363
 
                    "SELECT * FROM data WHERE id = %d LIMIT 1;",
364
 
                    (int)$dataId
365
 
                );
366
 
        try {
367
 
            $result = $this->_dbConnection->query($sql);
368
 
        }
369
 
        catch (Exception $e) {
370
 
            return false;
371
 
        }
372
 
 
373
 
        $image = $result->fetch_array(MYSQLI_ASSOC);
374
 
 
375
 
        // Fetch metadata from JP2 XML header
376
 
        $image_filepath = HV_JP2_DIR.$image['filepath'].'/'.$image['filename'];
377
 
        $xmlBox = $this->extractJP2MetaInfo($image_filepath);
378
 
 
379
 
        // Fetch metadata from the `datasources` table
380
 
        $datasource = $this->getDatasourceInformationFromSourceId(
381
 
            $image['sourceId']);
382
 
 
383
 
        return array_merge($image, $xmlBox, $datasource);
384
 
    }
385
 
 
386
 
    /**
387
 
     * Find available data that is closest to the requested time and
388
 
     * return its metadata from the database and xmlBox (if applicable).
389
 
     *
390
 
     * @param string $date A UTC date string of the form "2003-10-05T00:00:00Z"
391
 
     * @param int    $sourceId The data source's identifier in the database
392
 
     *
393
 
     * @return array Metadata related to the closest image or other data type.
394
 
     */
395
 
    public function getClosestData($date, $sourceId) {
396
 
        $data     = $this->getDataFromDatabase($date, $sourceId);
397
 
        $filename = HV_JP2_DIR.$data['filepath'].'/'.$data['filename'];
398
 
 
399
 
        if ( stripos($data['filename'], '.jp2') !== false ) {
400
 
            $xmlBox = $this->extractJP2MetaInfo($filename);
401
 
            return array_merge($data, $xmlBox);
402
 
        }
403
 
        return $data;
404
 
    }
405
 
 
406
 
    /**
407
 
     * Query the database for data that is closest to the requested time.
408
 
     *
409
 
     * @param string $date A UTC date string of the form "2003-10-05T00:00:00Z"
410
 
     * @param int    $sourceId The data source's identifier in the database
411
 
     *
412
 
     * @return array Associative array containing values from
413
 
     *               the `datasources` table.
414
 
     */
415
 
    public function getDataFromDatabase($date, $sourceId) {
416
 
        include_once HV_ROOT_DIR.'/src/php/Helper/DateTimeConversions.php';
417
 
 
418
 
        $this->_dbConnect();
419
 
 
420
 
        $datestr = isoDateToMySQL($date);
421
 
 
422
 
        $sql = sprintf(
423
 
                   "( SELECT "
424
 
                 .        "id, filepath, filename, date "
425
 
                 .   "FROM data "
426
 
                 .   "WHERE "
427
 
                 .       "sourceId " . " = %d AND "
428
 
                 .       "date "     . " <'%s' "
429
 
                 .   "ORDER BY date DESC "
430
 
                 .   "LIMIT 1 ) "
431
 
                 . "UNION ALL "
432
 
                 . "( SELECT "
433
 
                 .        "id, filepath, filename, date "
434
 
                 .   "FROM data "
435
 
                 .   "WHERE "
436
 
                 .       "sourceId " . " = %d AND "
437
 
                 .       "date "     . ">='%s' "
438
 
                 .   "ORDER BY date ASC "
439
 
                 .   "LIMIT 1 ) "
440
 
                 . "ORDER BY "
441
 
                 .     "ABS(TIMESTAMPDIFF(MICROSECOND, date, '%s') "
442
 
                 . ") LIMIT 1;",
443
 
                 (int)$sourceId,
444
 
                 $this->_dbConnection->link->real_escape_string(
445
 
                    $datestr),
446
 
                 (int)$sourceId,
447
 
                 $this->_dbConnection->link->real_escape_string(
448
 
                    $datestr),
449
 
                 $this->_dbConnection->link->real_escape_string(
450
 
                    $datestr)
451
 
               );
452
 
        try {
453
 
            $result = $this->_dbConnection->query($sql);
454
 
        }
455
 
        catch (Exception $e) {
456
 
            return false;
457
 
        }
458
 
 
459
 
        $data = $result->fetch_array(MYSQLI_ASSOC);
460
 
        if ( $data === null ) {
461
 
            $source = $this->_getDataSourceName($sourceId);
462
 
            throw new Exception("No data of the requested type ("
463
 
                               .$source.") are currently available.", 10);
464
 
        }
465
 
 
466
 
        return $data;
467
 
    }
468
 
 
469
 
    /**
470
 
     * Return the closest match from the `data` table whose time is on
471
 
     * or before the specified time.
472
 
     *
473
 
     * @param string $date     UTC date string like "2003-10-05T00:00:00Z"
474
 
     * @param int    $sourceId The data source identifier in the database
475
 
     *
476
 
     * @return array Array containing 1 row from the `data` table
477
 
     */
478
 
    public function getClosestDataBeforeDate($date, $sourceId) {
479
 
        include_once HV_ROOT_DIR.'/src/php/Helper/DateTimeConversions.php';
480
 
 
481
 
        $this->_dbConnect();
482
 
 
483
 
        $datestr = isoDateToMySQL($date);
484
 
 
485
 
        $sql = sprintf(
486
 
                   "SELECT filepath, filename, date "
487
 
                 . "FROM data "
488
 
                 . "WHERE "
489
 
                 .     "sourceId " . " = %d AND "
490
 
                 .     "date "     . "<='%s' "
491
 
                 . "ORDER BY date DESC "
492
 
                 . "LIMIT 1;",
493
 
                 (int)$sourceId,
494
 
                 $this->_dbConnection->link->real_escape_string(
495
 
                    $datestr)
496
 
               );
497
 
        try {
498
 
            $result = $this->_dbConnection->query($sql);
499
 
        }
500
 
        catch (Exception $e) {
501
 
            return false;
502
 
        }
503
 
 
504
 
        $data = $result->fetch_array(MYSQLI_ASSOC);
505
 
        if ( $data === null ) {
506
 
            $source = $this->_getDataSourceName($sourceId);
507
 
            throw new Exception( 'No '.$source.' data is available '
508
 
                               . 'on or before '.$date.'.', 11);
509
 
        }
510
 
 
511
 
        return $data;
512
 
    }
513
 
 
514
 
    /**
515
 
     * Return the closest match from the `data` table whose time is on
516
 
     * or after the specified time.
517
 
     *
518
 
     * @param string $date     UTC date string like "2003-10-05T00:00:00Z"
519
 
     * @param int    $sourceId The data source identifier in the database
520
 
     *
521
 
     * @return array Array containing 1 row from the `data` table
522
 
     */
523
 
    public function getClosestDataAfterDate($date, $sourceId) {
524
 
        include_once HV_ROOT_DIR.'/src/php/Helper/DateTimeConversions.php';
525
 
 
526
 
        $this->_dbConnect();
527
 
 
528
 
        $datestr = isoDateToMySQL($date);
529
 
 
530
 
        $sql = sprintf(
531
 
                   "SELECT filepath, filename, date "
532
 
                 . "FROM data "
533
 
                 . "WHERE "
534
 
                 .     "sourceId " . " = %d AND "
535
 
                 .     "date "     . ">='%s' "
536
 
                 . "ORDER BY date ASC "
537
 
                 . "LIMIT 1;",
538
 
                 (int)$sourceId,
539
 
                 $this->_dbConnection->link->real_escape_string(
540
 
                    $datestr)
541
 
               );
542
 
        try {
543
 
            $result = $this->_dbConnection->query($sql);
544
 
        }
545
 
        catch (Exception $e) {
546
 
            return false;
547
 
        }
548
 
 
549
 
        $data = $result->fetch_array(MYSQLI_ASSOC);
550
 
        if ( $data === null ) {
551
 
            $source = $this->_getDataSourceName($sourceId);
552
 
            throw new Exception( 'No '.$source.' data is available '
553
 
                               . 'on or after '.$date.'.', 11);
554
 
        }
555
 
 
556
 
        return $data;
557
 
    }
558
 
 
559
 
    /**
560
 
     * Get the human-readable name associated with the specified source id.
561
 
     *
562
 
     * @param  int    $sourceId The data source identifier in the database
563
 
     *
564
 
     * @return string Name of the data source associated with specified id
565
 
     */
566
 
    private function _getDataSourceName($sourceId) {
567
 
        $this->_dbConnect();
568
 
 
569
 
        $sql = sprintf(
570
 
                   "SELECT name FROM datasources WHERE id = %d LIMIT 1;",
571
 
                   (int)$sourceId
572
 
               );
573
 
        try {
574
 
            $result = $this->_dbConnection->query($sql);
575
 
        }
576
 
        catch (Exception $e) {
577
 
            return false;
578
 
        }
579
 
 
580
 
        $datasource = $result->fetch_array(MYSQLI_ASSOC);
581
 
        return $datasource['name'];
582
 
    }
583
 
 
584
 
    /**
585
 
     * Return the number `data` table rows matching a source and time range
586
 
     *
587
 
     * @param datetime $start    Query start time
588
 
     * @param datetime $end      Query end time
589
 
     * @param int      $sourceId The data source identifier in the database
590
 
     *
591
 
     * @return int The number of `data` rows matching a source and time range
592
 
     */
593
 
    public function getDataCount($start, $end, $sourceId) {
594
 
        include_once HV_ROOT_DIR.'/src/php/Helper/DateTimeConversions.php';
595
 
 
596
 
        $this->_dbConnect();
597
 
 
598
 
        $startDate = isoDateToMySQL($start);
599
 
        $endDate   = isoDateToMySQL($end);
600
 
 
601
 
        $sql = sprintf(
602
 
                   "SELECT COUNT(id) as count "
603
 
                 . "FROM data "
604
 
                 . "WHERE "
605
 
                 .     "sourceId " . " = %d AND "
606
 
                 .     "date BETWEEN '%s' AND '%s' "
607
 
                 . "LIMIT 1;",
608
 
                 (int)$sourceId,
609
 
                 $this->_dbConnection->link->real_escape_string(
610
 
                    $startDate),
611
 
                 $this->_dbConnection->link->real_escape_string(
612
 
                    $endDate)
613
 
               );
614
 
        try {
615
 
            $result = $this->_dbConnection->query($sql);
616
 
        }
617
 
        catch (Exception $e) {
618
 
            return false;
619
 
        }
620
 
 
621
 
        $data = $result->fetch_array(MYSQLI_ASSOC);
622
 
        return $data['count'];
623
 
    }
624
 
 
625
 
    /**
626
 
     * Return an array of data from a given data source within the specified
627
 
     * time range.
628
 
     *
629
 
     * @param datetime $start    Query start time
630
 
     * @param datetime $end      Query end time
631
 
     * @param int      $sourceId The data source identifier in the database
632
 
     *
633
 
     * @return array Array containing matched rows from the `data` table
634
 
     */
635
 
    public function getDataRange($start, $end, $sourceId) {
636
 
        include_once HV_ROOT_DIR.'/src/php/Helper/DateTimeConversions.php';
637
 
 
638
 
        $this->_dbConnect();
639
 
 
640
 
        $data      = array();
641
 
        $startDate = isoDateToMySQL($start);
642
 
        $endDate   = isoDateToMySQL($end);
643
 
 
644
 
        $sql = sprintf(
645
 
                   "SELECT * "
646
 
                 . "FROM data "
647
 
                 . "WHERE "
648
 
                 .     "sourceId = %d AND "
649
 
                 .     "date BETWEEN '%s' AND '%s' "
650
 
                 . "ORDER BY date ASC;",
651
 
                 (int)$sourceId,
652
 
                 $this->_dbConnection->link->real_escape_string(
653
 
                    $startDate),
654
 
                 $this->_dbConnection->link->real_escape_string(
655
 
                    $endDate)
656
 
               );
657
 
        try {
658
 
            $result = $this->_dbConnection->query($sql);
659
 
        }
660
 
        catch (Exception $e) {
661
 
            return false;
662
 
        }
663
 
 
664
 
        $result_array = Array();
665
 
        while ( $row = $result->fetch_array(MYSQLI_ASSOC) ) {
666
 
            array_push($data, $row);
667
 
        }
668
 
 
669
 
        return $data;
670
 
    }
671
 
 
672
 
    /**
673
 
     * Extract metadata from JP2 image file's XML header
674
 
     *
675
 
     * @param string $image_filepath Full path to JP2 image file
676
 
     *
677
 
     * @return array A subset of the information stored in the jp2 header
678
 
     */
679
 
    public function extractJP2MetaInfo($image_filepath) {
680
 
 
681
 
        include_once HV_ROOT_DIR.'/src/php/Image/JPEG2000/JP2ImageXMLBox.php';
682
 
 
683
 
        try {
684
 
            $xmlBox = new Image_JPEG2000_JP2ImageXMLBox($image_filepath);
685
 
 
686
 
            $dimensions              = $xmlBox->getImageDimensions();
687
 
            $refPixel                = $xmlBox->getRefPixelCoords();
688
 
            $imageScale              = (float) $xmlBox->getImagePlateScale();
689
 
            $dsun                    = (float) $xmlBox->getDSun();
690
 
            $sunCenterOffsetParams   = $xmlBox->getSunCenterOffsetParams();
691
 
            $layeringOrder           = $xmlBox->getLayeringOrder();
692
 
 
693
 
            // Normalize image scale
694
 
            $imageScale = $imageScale * ($dsun / HV_CONSTANT_AU);
695
 
 
696
 
            $meta = array(
697
 
                "scale"      => $imageScale,
698
 
                "width"      => (int) $dimensions[0],
699
 
                "height"     => (int) $dimensions[1],
700
 
                "refPixelX"  => (float) $refPixel[0],
701
 
                "refPixelY"  => (float) $refPixel[1],
702
 
                "sunCenterOffsetParams" => $sunCenterOffsetParams,
703
 
                "layeringOrder"         => $layeringOrder
704
 
            );
705
 
        }
706
 
        catch (Exception $e) {
707
 
            throw new Exception(
708
 
                sprintf("Unable to process XML Header for %s: %s",
709
 
                        $image_filepath,
710
 
                        $e->getMessage()
711
 
                       ), 13);
712
 
        }
713
 
 
714
 
        return $meta;
715
 
    }
716
 
 
717
 
    /**
718
 
     * Fetch datasource properties from the database.
719
 
     *
720
 
     * @param   int $sourceId Identifier in the `datasources` and
721
 
     *                        `datasource_property` tables
722
 
     *
723
 
     * @return  Array   Datasource metadata
724
 
     */
725
 
    public function getDatasourceInformationFromSourceId($sourceId) {
726
 
        $this->_dbConnect();
727
 
 
728
 
        $sql  = sprintf(
729
 
                    "SELECT "
730
 
                  .     "dp.label, "
731
 
                  .     "dp.name, "
732
 
                  .     "ds.name as 'nickname', "
733
 
                  .     "ds.layeringOrder "
734
 
                  . "FROM "
735
 
                  .     "datasource_property dp "
736
 
                  . "LEFT JOIN "
737
 
                  .     "datasources ds ON dp.sourceId = ds.id "
738
 
                  . "WHERE "
739
 
                  .     "sourceId = %d "
740
 
                  . "ORDER BY uiOrder ASC;",
741
 
                  (int)$sourceId
742
 
                );
743
 
        try {
744
 
            $result = $this->_dbConnection->query($sql);
745
 
        }
746
 
        catch (Exception $e) {
747
 
            return false;
748
 
        }
749
 
 
750
 
        $uiOrder = 0;
751
 
        $result_array = Array();
752
 
        $result_array['uiLabels'] = Array();
753
 
        while ( $row = $result->fetch_array(MYSQLI_ASSOC) ) {
754
 
            $result_array['uiLabels'][] = Array('label'=>$row['label'], 'name'=>$row['name']);
755
 
            $nickname      = $row['nickname'];
756
 
            $layeringOrder = $row['layeringOrder'];
757
 
            $uiOrder++;
758
 
        }
759
 
        $result_array['name']          = $nickname;
760
 
        $result_array['layeringOrder'] = $layeringOrder;
761
 
 
762
 
        return $result_array;
763
 
    }
764
 
 
765
 
    /**
766
 
     * Return `datasource` id, name, layeringOrder for the matched labels
767
 
     *
768
 
     * @param  array Array of `datasource_property`.name in uiOrder order
769
 
     *
770
 
     * @return array Array of `datasource` id, name, layeringOrder
771
 
     */
772
 
    public function getDatasourceInformationFromNames($property_array) {
773
 
        $this->_dbConnect();
774
 
 
775
 
        $letters = array('a','b','c','d','e');
776
 
        $select_clause = array('ds.id', 'ds.name', 'ds.layeringOrder');
777
 
        $from_clause   = array();
778
 
        $where_clause  = array();
779
 
 
780
 
 
781
 
        foreach ($property_array as $i=>$property) {
782
 
            $i = intval($i);
783
 
            $property = $this->_dbConnection->link->real_escape_string(
784
 
                $property);
785
 
 
786
 
            $select_clause[] = $letters[$i].'.label AS '.$letters[$i].'_label';
787
 
            $from_clause[]  = 'datasource_property '.$letters[$i];
788
 
            if ($i > 0) {
789
 
                $where_clause[] = 'ds.id=a.sourceId';
790
 
                $where_clause[] = 'a.sourceId='.$letters[$i].'.sourceId';
791
 
            }
792
 
            $where_clause[] = $letters[$i].'.name="'.$property.'"';
793
 
            $where_clause[] = $letters[$i].'.uiOrder='.++$i;
794
 
        }
795
 
        $sql  = 'SELECT ' . implode(', ', $select_clause) . ' ';
796
 
        $sql .= 'FROM datasources ds, ' . implode(', ', $from_clause);
797
 
        $sql .= ' WHERE ' . implode(' AND ', $where_clause);
798
 
 
799
 
        try {
800
 
            $result = $this->_dbConnection->query($sql);
801
 
        }
802
 
        catch (Exception $e) {
803
 
            return false;
804
 
        }
805
 
 
806
 
        $row = $result->fetch_array(MYSQLI_ASSOC);
807
 
 
808
 
        $result_array = Array();
809
 
        $result_array['id']            = $row['id'];
810
 
        $result_array['name']          = $row['name'];
811
 
        $result_array['layeringOrder'] = $row['layeringOrder'];
812
 
        $result_array['uiLabels']      = Array();
813
 
 
814
 
        foreach ($property_array as $i=>$property) {
815
 
            $result_array['uiLabels'][] = Array(
816
 
                'label' => $row[$letters[$i].'_label'],
817
 
                'name'  => $property);
818
 
        }
819
 
 
820
 
        return $result_array;
821
 
    }
822
 
 
823
 
    /**
824
 
     * Return the UI labels for the matched `datasource_property` names
825
 
     *
826
 
     * @param  array Array of `datasource_property`.name in uiOrder order
827
 
     *
828
 
     * @return array Array of `datasource_property` label in uiOrder order
829
 
     */
830
 
    public function getDataSourceLabels($property_array) {
831
 
        $this->_dbConnect();
832
 
 
833
 
        $letters = array('a','b','c','d','e');
834
 
        $select_clause = array();
835
 
        $join_clause   = array();
836
 
        $where_clause  = array();
837
 
 
838
 
        foreach ($property_array as $i=>$property) {
839
 
            $i = intval($i);
840
 
            $property = $this->_dbConnection->link->real_escape_string(
841
 
                $property);
842
 
 
843
 
            $select_clause[] = $letters[$i].'.label as "'.$i.'"';
844
 
 
845
 
            if ( $i > 0 ) {
846
 
                $join_clause[] = 'LEFT JOIN datasource_property '.$letters[$i];
847
 
                $join_clause[] = 'ON a.sourceId = '.$letters[$i].'.sourceId';
848
 
            }
849
 
 
850
 
            $where_clause[] = $letters[$i].'.name="'.$property.'"';
851
 
            $where_clause[] = $letters[$i].'.uiOrder='.++$i;
852
 
        }
853
 
 
854
 
        $sql  = 'SELECT ' . implode(', ', $select_clause);
855
 
        $sql .= ' FROM datasource_property a ';
856
 
        $sql .= implode(' ', $join_clause);
857
 
        $sql .= ' WHERE ' . implode(' AND ', $where_clause);
858
 
 
859
 
        try {
860
 
            $result = $this->_dbConnection->query($sql);
861
 
        }
862
 
        catch (Exception $e) {
863
 
            return false;
864
 
        }
865
 
 
866
 
        $row = $result->fetch_array();
867
 
        foreach ($property_array as $i=>$property) {
868
 
            $return_array[$row[$i]] = $property;
869
 
        }
870
 
 
871
 
        return $return_array;
872
 
    }
873
 
 
874
 
 
875
 
    /**
876
 
     * Return `datasource` identifier for the matched labels
877
 
     *
878
 
     * @param  array Array of `datasource_property`.name in uiOrder order
879
 
     *
880
 
     * @return int   The matched sourceId.
881
 
     */
882
 
    public function getSourceId($property_array) {
883
 
        $this->_dbConnect();
884
 
 
885
 
        $letters = array('a','b','c','d','e');
886
 
        $from_clause  = array();
887
 
        $where_clause = array();
888
 
 
889
 
        $sql = "SELECT a.sourceId AS 'sourceId' "
890
 
             . "FROM ";
891
 
        foreach ($property_array as $i=>$property) {
892
 
            $i = (int)$i;
893
 
            $property = mysqli_real_escape_string($this->_dbConnection->link,
894
 
                $property);
895
 
 
896
 
            $from_clause[]  = 'datasource_property '.$letters[$i];
897
 
            if ($i > 0) {
898
 
                $where_clause[] = 'a.sourceId='.$letters[$i].'.sourceId';
899
 
            }
900
 
            $where_clause[] = $letters[$i].'.name="'.$property.'"';
901
 
            $where_clause[] = $letters[$i].'.uiOrder='.++$i;
902
 
        }
903
 
        $sql .= implode(', ', $from_clause);
904
 
        $sql .= ' WHERE ' . implode(' AND ', $where_clause);
905
 
 
906
 
        try {
907
 
            $result = $this->_dbConnection->query($sql);
908
 
            if ( $result->num_rows != 1 ) {
909
 
                return false;
910
 
            }
911
 
        }
912
 
        catch (Exception $e) {
913
 
            return false;
914
 
        }
915
 
 
916
 
        $datasource = $result->fetch_array(MYSQLI_ASSOC);
917
 
        return $datasource['sourceId'];
918
 
    }
919
 
 
920
 
    /**
921
 
     * Fetche the date of the oldest data from the `data` table for the
922
 
     * specified data source identifier.
923
 
     *
924
 
     * @param  int  $sourceId  Data source identifier
925
 
     *
926
 
     * @return date Date of the oldest row data
927
 
     */
928
 
    public function getOldestData($sourceId) {
929
 
        $this->_dbConnect();
930
 
 
931
 
        $sql = sprintf(
932
 
                   'SELECT date '
933
 
                 . 'FROM data '
934
 
                 . 'WHERE sourceId = %d '
935
 
                 . 'ORDER BY date ASC '
936
 
                 . 'LIMIT 1;',
937
 
                 (int)$sourceId
938
 
               );
939
 
        try {
940
 
            $result = $this->_dbConnection->query($sql);
941
 
        }
942
 
        catch (Exception $e) {
943
 
            return false;
944
 
        }
945
 
 
946
 
        $data = $result->fetch_array(MYSQLI_ASSOC);
947
 
        return $data['date'];
948
 
    }
949
 
 
950
 
    /**
951
 
     * Fetche the date of the newest data from the `data` table for the
952
 
     * specified data source identifier.
953
 
     *
954
 
     * @param  int  $sourceId  Data source identifier
955
 
     *
956
 
     * @return date Date of the newest row data
957
 
     */
958
 
    public function getNewestData($sourceId) {
959
 
        $this->_dbConnect();
960
 
 
961
 
        $sql = sprintf(
962
 
                   'SELECT date '
963
 
                 . 'FROM data '
964
 
                 . 'WHERE sourceId = %d '
965
 
                 . 'ORDER BY date DESC '
966
 
                 . 'LIMIT 1;',
967
 
                 (int)$sourceId
968
 
               );
969
 
        try {
970
 
            $result = $this->_dbConnection->query($sql);
971
 
        }
972
 
        catch (Exception $e) {
973
 
            return false;
974
 
        }
975
 
 
976
 
        $data = $result->fetch_array(MYSQLI_ASSOC);
977
 
        return $data['date'];
978
 
    }
979
 
 
980
 
    /**
981
 
     * Return a sorted array of Instruments with a sorted sub-array
982
 
     * of datasource IDs and datasource names.
983
 
     *
984
 
     * @return array Sorted array of instruments with associated sources
985
 
     */
986
 
    public function getDataSourcesByInstrument() {
987
 
        $this->_dbConnect();
988
 
 
989
 
        $sql = 'SELECT '
990
 
             .     'dsp.name as "instName", '
991
 
             .     'ds.id, '
992
 
             .     'ds.name as "sourceName" '
993
 
             . 'FROM '
994
 
             .     'datasources ds '
995
 
             . 'LEFT JOIN '
996
 
             .     'datasource_property dsp ON dsp.sourceId = ds.id '
997
 
             . 'WHERE '
998
 
             .     'dsp.label = "Instrument" '
999
 
             . 'GROUP BY '
1000
 
             .     'dsp.name, ds.name '
1001
 
             . 'ORDER BY dsp.name';
1002
 
        try {
1003
 
            $result = $this->_dbConnection->query($sql);
1004
 
        }
1005
 
        catch (Exception $e) {
1006
 
            return false;
1007
 
        }
1008
 
 
1009
 
        $return_array = array();
1010
 
        while ( $row = $result->fetch_array(MYSQLI_ASSOC) ) {
1011
 
            $return_array[$row['instName']][] = array(
1012
 
                'id'   => $row['id'],
1013
 
                'name' => $row['sourceName'] );
1014
 
        }
1015
 
 
1016
 
        return $return_array;
1017
 
    }
1018
 
 
1019
 
    /**
1020
 
     * Return a hierarchial list of the known data sources in one of
1021
 
     * two formats.
1022
 
     *
1023
 
     * If $verbose is True, an alternative data structure is returned for
1024
 
     * use with JHelioviewer.  A hard-coded list of datasources is excluded
1025
 
     * from the output by default, to prevent JHelioviewer crashes.
1026
 
     *
1027
 
     * When $verbose is True, $enable may contain a string of top-level
1028
 
     * data sources to re-enable.  Example: '[STEREO_A,STEREO_B,PROBA2]'
1029
 
     *
1030
 
     * @param bool   $verbose   true or false
1031
 
     * @param string $enable    array string of top-level sources to include
1032
 
     *
1033
 
     * @return array A tree representation of the known data sources
1034
 
     */
1035
 
    public function getDataSources($verbose=false, $enable=null) {
1036
 
        $this->_dbConnect();
1037
 
 
1038
 
        // Support up to 5 levels of datasource hierarchy
1039
 
        $letters = array('a','b','c','d','e');
1040
 
 
1041
 
        $sql = 'SELECT '
1042
 
             .     's.name '           .'AS nickname, '
1043
 
             .     's.id '             .'AS id, '
1044
 
             .     's.enabled '        .'AS enabled, '
1045
 
             .     's.layeringOrder '  .'AS layeringOrder, '
1046
 
             .     's.units '          .'AS units';
1047
 
 
1048
 
        foreach ($letters as $i=>$letter) {
1049
 
            $sql .= ', ';
1050
 
            $sql .= $letter.'.name '        .'AS '.$letter.'_name, ';
1051
 
            $sql .= $letter.'.description ' .'AS '.$letter.'_description, ';
1052
 
            $sql .= $letter.'.label '       .'AS '.$letter.'_label';
1053
 
        }
1054
 
 
1055
 
        $sql .= ' FROM datasources s ';
1056
 
 
1057
 
        foreach ($letters as $i=>$letter) {
1058
 
            $sql .= 'LEFT JOIN datasource_property '.$letter.' ';
1059
 
            $sql .= 'ON s.id='.$letter.'.sourceId ';
1060
 
            $sql .= 'AND '.$letter.'.uiOrder='.++$i.' ';
1061
 
        }
1062
 
 
1063
 
        // Verbose mode is for JHelioviewer
1064
 
        // Older versions may crash if exposed to new "observatories"
1065
 
        // By default, only include observatories in the array below
1066
 
        // Also include any observatories specified in the $enable parameter
1067
 
        if ($verbose) {
1068
 
            $include_arr = array("SOHO","SDO");
1069
 
 
1070
 
            // Override hidden observatories if specified
1071
 
            foreach($enable as $show) {
1072
 
                if ( !in_array($show, $include_arr) ) {
1073
 
                    $include_arr[] = $show;
1074
 
                }
1075
 
            }
1076
 
 
1077
 
            // Prepare include list for "IN" clause
1078
 
            $included = "(";
1079
 
            foreach ($include_arr as $show) {
1080
 
                $show = $this->_dbConnection->link->real_escape_string(
1081
 
                    $show);
1082
 
                $included .= "'$show',";
1083
 
            }
1084
 
            $included = substr($included, 0, -1).")";
1085
 
 
1086
 
            if (sizeOf($include_arr) > 0) {
1087
 
                $sql = substr($sql, 0, -1)." WHERE a.name IN $included";
1088
 
            } else {
1089
 
                $sql = substr($sql, 0, -1)."";
1090
 
            }
1091
 
 
1092
 
            $sql .= ' ORDER BY a.name DESC;';
1093
 
 
1094
 
        }
1095
 
 
1096
 
        // Use UTF-8 for responses
1097
 
        $this->_dbConnection->setEncoding('utf8');
1098
 
 
1099
 
        // Fetch available data-sources
1100
 
        $result = $this->_dbConnection->query($sql);
1101
 
        $sources = array();
1102
 
        while ($row = $result->fetch_array(MYSQLI_ASSOC)) {
1103
 
            array_push($sources, $row);
1104
 
        }
1105
 
 
1106
 
        // Convert results into a more easily traversable tree structure
1107
 
        $tree = array();
1108
 
        foreach ($sources as $source) {
1109
 
 
1110
 
            // Only include if data is available for the specified source
1111
 
            // as flagged in the `datasources` table
1112
 
            if ( !(bool)$source["enabled"] ) {
1113
 
                continue;
1114
 
            }
1115
 
 
1116
 
            // Data Availability
1117
 
            $newest = $this->getNewestData($source['id']);
1118
 
            $oldest = $this->getOldestData($source['id']);
1119
 
 
1120
 
            // Determine depth of tree for this data source
1121
 
            // And populate uiLabel array
1122
 
            $depth = 0;
1123
 
            $uiLabels = array();
1124
 
            foreach ($letters as $i=>$letter) {
1125
 
                if ( $source[$letter.'_name'] !== null ) {
1126
 
                    $uiLabels[$i] = array(
1127
 
                        'label'=>$source[$letters[$i].'_label'],
1128
 
                        'name' =>$source[$letters[$i].'_name']);
1129
 
                    $depth = ++$i;
1130
 
                }
1131
 
            }
1132
 
 
1133
 
            // Normal (non-verbose) format for Helioviewer.org
1134
 
            if (!$verbose) {
1135
 
 
1136
 
                $r = &$tree;
1137
 
                foreach ($letters as $index=>$letter) {
1138
 
                    $key = $source[$letter.'_name'];
1139
 
                    if ( ++$index == $depth ) {
1140
 
                        $r[$key]['sourceId']      = (int)$source["id"];
1141
 
                        $r[$key]['nickname']      = $source["nickname"];
1142
 
                        $r[$key]['layeringOrder'] =
1143
 
                            (int)$source["layeringOrder"];
1144
 
                        $r[$key]['start']         = $oldest;
1145
 
                        $r[$key]['end']           = $newest;
1146
 
                        $r[$key]['uiLabels']      = $uiLabels;
1147
 
                        break;
1148
 
                    }
1149
 
                    $r = &$r[$key];
1150
 
                }
1151
 
            }
1152
 
            // Verbose format for JHelioviewer
1153
 
            else {
1154
 
 
1155
 
                $r = &$tree;
1156
 
                foreach ($letters as $index=>$letter) {
1157
 
                    $key   = $source[$letter.'_name'];
1158
 
                    $name  = $key;
1159
 
                    $desc  = $source[$letter.'_description'];
1160
 
                    $label = $source[$letter.'_label'];
1161
 
 
1162
 
                    $r[$key]['name']        = $name;
1163
 
                    $r[$key]['description'] = $desc;
1164
 
                    $r[$key]['label']       = $label;
1165
 
 
1166
 
                    if ( ++$index == $depth ) {
1167
 
 
1168
 
                        if (preg_match("/^\d*$/", $name)) {
1169
 
                            # \u205f = \xE2\x81\x9F = MEDIUM MATHEMATICAL SPACE
1170
 
                            $name = $name."\xE2\x81\x9F".$source['units'];
1171
 
                        }
1172
 
                        else {
1173
 
                            $name = ucwords(str_replace("-", " ", $name));
1174
 
                        }
1175
 
 
1176
 
                        $r[$key]['name']          = $name;
1177
 
                        $r[$key]['description']   = $desc;
1178
 
                        $r[$key]['nickname']      = $source["nickname"];
1179
 
                        $r[$key]['sourceId']      = (int)$source["id"];
1180
 
                        $r[$key]['layeringOrder'] =
1181
 
                            (int)$source["layeringOrder"];
1182
 
                        $r[$key]['start']         = $oldest;
1183
 
                        $r[$key]['end']           = $newest;
1184
 
                        $r[$key]['label']         = $label;
1185
 
                        break;
1186
 
                    }
1187
 
 
1188
 
                    $r = &$r[$key]['children'];
1189
 
                }
1190
 
            }
1191
 
 
1192
 
        }
1193
 
 
1194
 
        // Set defaults for verbose mode (JHelioviewer)
1195
 
        if ($verbose) {
1196
 
            $tree["SDO"]["default"]=true;
1197
 
            $tree["SDO"]["children"]["AIA"]["default"]=true;
1198
 
            $tree["SDO"]["children"]["AIA"]["children"]["171"]["default"]=true;
1199
 
        }
1200
 
 
1201
 
        return $tree;
1202
 
    }
1203
 
 
1204
 
    /**
1205
 
     * Return the full path to the date file from the specified source
1206
 
     * most closely matching the given date.
1207
 
     *
1208
 
     * @param string $date     A UTC date string like "2003-10-05T00:00:00Z"
1209
 
     * @param int    $sourceId The data source identifier in the database
1210
 
     *
1211
 
     * @return string Full path to the local data file
1212
 
     *
1213
 
     */
1214
 
    public function getDataFilePath($date, $sourceId) {
1215
 
        $img = $this->getDataFromDatabase($date, $sourceId);
1216
 
 
1217
 
        return $img['filepath'].'/'.$img['filename'];
1218
 
    }
1219
 
 
1220
 
    /**
1221
 
     * Return the full path to the requested data file.
1222
 
     *
1223
 
     * @param int $id Identifier in the `data` table
1224
 
     *
1225
 
     * @return string Full path to the local data file
1226
 
     */
1227
 
    public function getDataFilePathFromId($dataId) {
1228
 
        $this->_dbConnect();
1229
 
 
1230
 
        $sql = sprintf(
1231
 
                   'SELECT concat(filepath, "/", filename) AS filepath '
1232
 
                 . 'FROM data '
1233
 
                 . 'WHERE id = %d '
1234
 
                 . 'LIMIT 1',
1235
 
                 (int)$dataId
1236
 
               );
1237
 
        try {
1238
 
            $result = $this->_dbConnection->query($sql);
1239
 
        }
1240
 
        catch (Exception $e) {
1241
 
            return false;
1242
 
        }
1243
 
 
1244
 
        $data = $result->fetch_array(MYSQLI_ASSOC);
1245
 
        return $data['filepath'];
1246
 
    }
1247
 
 
1248
 
    /**
1249
 
     * Return from the database the parameters that were used to generate
1250
 
     * a screenshot.
1251
 
     *
1252
 
     * @param int Unique screenshot identifier
1253
 
     *
1254
 
     * @return array Screenshot metadata
1255
 
     */
1256
 
    public function getScreenshotMetadata($screenshotId) {
1257
 
        $this->_dbConnect();
1258
 
 
1259
 
        $sql = sprintf('SELECT *, AsText(regionOfInterest) as roi ' .
1260
 
            'FROM screenshots WHERE id=%d LIMIT 1;',
1261
 
             (int)$screenshotId
1262
 
        );
1263
 
        try {
1264
 
            $result = $this->_dbConnection->query($sql);
1265
 
        }
1266
 
        catch (Exception $e) {
1267
 
            return false;
1268
 
        }
1269
 
 
1270
 
        return $result->fetch_array(MYSQLI_ASSOC);
1271
 
    }
1272
 
}
1273
 
?>