Issues (6)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Api.php (6 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
namespace Narcoticfresh\Shotwell;
4
5
/**
6
 * Simple API for Shotwell sqlite databases
7
 *
8
 * @package Narcoticfresh\Shotwell
9
 * @author  Dario Nuevo
10
 * @license https://opensource.org/licenses/gpl-3.0.html GPL-3.0
11
 * @link    https://github.com/narcoticfresh/shotwell
12
 */
13
class Api
14
{
15
16
    /**
17
     * Constant for photo type
18
     */
19
    const TYPE_PHOTO = "PHOTO";
20
21
    /**
22
     * Constant for video type
23
     */
24
    const TYPE_VIDEO = "VIDEO";
25
26
    /**
27
     * Type map, mapping the ObjectID prefixes to our constants
28
     *
29
     * @var array
30
     */
31
    private $typeMap = array(
32
        self::TYPE_PHOTO => 'thumb',
33
        self::TYPE_VIDEO => 'video-'
34
    );
35
36
    /**
37
     * database
38
     *
39
     * @var \PDO
40
     */
41
    private $db;
42
43
    /**
44
     * Local cache array
45
     *
46
     * @var array
47
     */
48
    private $tagMap = null;
49
50
    /**
51
     * Api constructor.
52
     *
53
     * @param string $dbPath Path to sqlite file
54
     *
55
     * @throws \Exception
56
     */
57 11
    public function __construct($dbPath)
58
    {
59 11
        if (!file_exists($dbPath) || !is_readable($dbPath)) {
60 1
            throw new \Exception("Database with path '" . $dbPath ."' doesn't exist or isn't readable!");
61
        }
62
63 11
        $this->db = new \PDO('sqlite:' . $dbPath);
64 11
    }
65
66
    /**
67
     * Returns an array of everything in the database, videos and photos mixed
68
     *
69
     * @return array array of simple array structures containing the data from the database
70
     */
71 1
    public function getAll()
72
    {
73 1
        return $this->searchAllWithCondition();
74
    }
75
76
    /**
77
     * Returns an array of all photos in the database
78
     *
79
     * @return array array of simple array structures containing the data from the database
80
     */
81 1
    public function getAllPhotos()
82
    {
83 1
        return $this->getItem(self::TYPE_PHOTO);
84
    }
85
86
    /**
87
     * Returns an array of all videos in the database
88
     *
89
     * @return array array of simple array structures containing the data from the database
90
     */
91 1
    public function getAllVideos()
92
    {
93 1
        return $this->getItem(self::TYPE_VIDEO);
94
    }
95
96
    /**
97
     * Returns a given photo by it's ID in PhotoTable
98
     *
99
     * @param string $id ID
100
     *
101
     * @return array
102
     */
103 5
    public function getPhotoById($id)
104
    {
105 5
        return $this->getItem(self::TYPE_PHOTO, $id);
106
    }
107
108
    /**
109
     * Returns a given video by it's ID in VideoTable
110
     *
111
     * @param string $id ID
112
     *
113
     * @return array
114
     */
115 6
    public function getVideoById($id)
116
    {
117 6
        return $this->getItem(self::TYPE_VIDEO, $id);
118
    }
119
120
    /**
121
     * Returns all tags associated with a given Object ID. Make sure to get an Object ID first by
122
     * calling getObjectIdByNumericId().
123
     *
124
     * @param string $objectId Object ID.
125
     *
126
     * @return bool Either an array of tags or false if the object doesn't exist
127
     */
128 7
    public function getTagsByObjectId($objectId)
129
    {
130 7
        if (is_null($this->tagMap)) {
131 7
            $this->tagMap = $this->getItemTagMap();
132
        }
133
134 7
        if (isset($this->tagMap[$objectId])) {
135 7
            $ret = $this->tagMap[$objectId];
136
        } else {
137 2
            return false;
138
        }
139
140 7
        return $ret;
141
    }
142
143
    /**
144
     * Sets tags on a given item using an Oject ID. Make sure to get an Object ID first by
145
     * calling getObjectIdByNumericId(). This sets the tags to the ones you pass.
146
     *
147
     * @param string $objectId Object ID
148
     * @param array  $tags     An array of strings containing your tags
149
     *
150
     * @return bool true if all is good, false otherwise
151
     */
152 3
    public function setItemTags($objectId, array $tags)
153
    {
154 3
        $currentTags = $this->getTagsByObjectId($objectId);
155
156 3
        if ($currentTags === false) {
157 1
            return false;
158
        }
159
160
        // get diff - those need to be added
161 3
        $tagDiffAdd = array_diff($tags, $currentTags);
162
163
        // get diff otherway - those need to be removed..
164 3
        $tagDiffRemove = array_diff($currentTags, $tags);
165
166 3
        foreach ($tagDiffAdd as $tagName) {
167 2
            $this->manipulateItemOnTag($tagName, 'add', $objectId);
168
        }
169
170 3
        foreach ($tagDiffRemove as $tagName) {
171 3
            $this->manipulateItemOnTag($tagName, 'remove', $objectId);
172
        }
173
174 3
        $this->tagMap = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $tagMap.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
175
176 3
        return true;
177
    }
178
179
    /**
180
     * This is a private function for doing common stuff on the tag. So not from item perspective.
181
     *
182
     * @param string $tagName  the tag
183
     * @param string $whatToDo What you want to do (either 'add' or 'remove')
184
     * @param string $objectId Object ID
185
     *
186
     * @throws Exception
187
     *
188
     * @return boolean true if all seems ok, false otherwise
189
     */
190 3
    private function manipulateItemOnTag($tagName, $whatToDo, $objectId)
191
    {
192 3
        $thisTagData = $this->getTag($tagName, true);
193 3
        $ret = false;
194
195 3
        if (is_array($thisTagData)) {
196 3
            $thisTagItems = explode(',', $thisTagData['photo_id_list']);
197 3
            $setKey = array_search($objectId, $thisTagItems);
198
199
            // what to do?
200 3
            if ($whatToDo == 'add') {
201 2
                if ($setKey === false) {
202 2
                    $thisTagItems[] = $objectId;
203
                }
204 3
            } elseif ($whatToDo == 'remove') {
205 3
                if ($setKey !== false) {
206 3
                    unset($thisTagItems[$setKey]);
207
                }
208
            }
209
210 3
            $ret = $this->setTagItems($tagName, $thisTagItems);
211
        }
212
213 3
        return $ret;
214
    }
215
216
    /**
217
     * Sets items on a tag
218
     *
219
     * @param string $tag   the tag
220
     * @param array  $items items
221
     *
222
     * @return bool true if all ok, false otherwise
223
     */
224 3
    private function setTagItems($tag, array $items)
225
    {
226 3
        $thisTagId = $this->getTagId($tag);
227 3
        $ret = false;
228
229 3
        if ($thisTagId !== false) {
230 3
            $q = "UPDATE TagTable SET `photo_id_list` = ? WHERE id = ?";
231
232 3
            $res = $this->db->prepare($q);
233
234 3
            $saveString = implode(',', $items).',';
235
236
            // ensure we don't save ",," somewhere..
237 3
            $saveString = str_replace(',,', ',', $saveString);
238
239 3
            $res->execute([
240 3
                $saveString,
241 3
                $thisTagId
242
            ]);
243
244 3
            $ret = true;
245
        }
246
247 3
        return $ret;
248
    }
249
250
    /**
251
     * Sets the rating on a tag using the Object ID. Make sure to get an Object ID first by
252
     * calling getObjectIdByNumericId().
253
     *
254
     * @param string $objectId Object ID
255
     * @param int    $rating   Rating (1-5)
256
     *
257
     * @return bool true if all ok, false otherwise
258
     * @throws \Exception
259
     */
260 3
    public function setItemRating($objectId, $rating)
261
    {
262 3
        if (!is_numeric($rating)) {
263 1
            throw new \Exception(sprintf("Rating must be numeric, '%s' given", $rating));
264
        }
265
266 2
        $thisTable = null;
267 2
        if ($this->getTypeByObjectId($objectId) == self::TYPE_PHOTO) {
268 1
            $thisTable = 'PhotoTable';
269
        }
270 2
        if ($this->getTypeByObjectId($objectId) == self::TYPE_VIDEO) {
271 2
            $thisTable = 'VideoTable';
272
        }
273
274 2
        if (is_null($thisTable)) {
275 1
            return false;
276
        }
277
278 2
        $item = $this->getItemByObjectId($objectId);
279
280 2
        if (!isset($item['id'])) {
281 1
            return false;
282
        }
283
284 1
        $q = "UPDATE `" . $thisTable . "` SET rating=? WHERE id=?";
285
286 1
        $res = $this->db->prepare($q);
287 1
        $ret = $res->execute(array(
288 1
            $rating,
289 1
            $item['id']
290
        ));
291
292 1
        return $ret;
293
    }
294
295
    /**
296
     * Removes all tags from a given item using Object ID. Make sure to get an Object ID first by
297
     * calling getObjectIdByNumericId().
298
     *
299
     * @param string $objectId Object ID
300
     *
301
     * @return void
302
     */
303 1
    public function removeAllItemTags($objectId)
304
    {
305 1
        return $this->setItemTags($objectId, []);
306
    }
307
308
    /**
309
     * Gets an item
310
     *
311
     * @param string      $itemType What type of item
312
     * @param null|string $objectId The object ID
313
     *
314
     * @return array the item
315
     */
316 7
    private function getItem($itemType, $objectId = null)
317
    {
318 7
        if ($itemType == self::TYPE_PHOTO) {
319 5
            $tableName = 'PhotoTable';
320 6
        } elseif ($itemType == self::TYPE_VIDEO) {
321 6
            $tableName = 'VideoTable';
322
        }
323
324 7
        if (!is_null($objectId)) {
325 7
            $query = 'SELECT * FROM `' . $tableName . '` WHERE id=?';
0 ignored issues
show
The variable $tableName does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
326 7
            $params = [$objectId];
327
        } else {
328 1
            $query = 'SELECT * FROM ' . $tableName;
329 1
            $params = [];
330
        }
331
332 7
        $res = $this->db->prepare($query);
333 7
        $res->execute($params);
334
335 7
        $ret = array();
336
337 7
        while (($data = $res->fetch(\PDO::FETCH_ASSOC))) {
338 6
            if (is_array($data) && isset($data['id'])) {
339 6
                $data['object_id'] = $this->getObjectIdByNumericId($itemType, $data['id']);
340 6
                $data['tags'] = $this->getTagsByObjectId($data['object_id']);
341 6
                if ($data['tags'] === false) {
342 1
                    $data['tags'] = [];
343
                }
344 6
                $data['type'] = $itemType;
345 6
                $ret[] = $data;
346
            }
347
        }
348
349 7
        if (!is_null($objectId) && isset($ret[0])) {
350 6
            return $ret[0];
351
        }
352
353 2
        return $ret;
354
    }
355
356
    /**
357
     * Gets an item by Object ID
358
     *
359
     * @param string $objectId Object ID
360
     *
361
     * @return array|bool Either the item data or false
362
     */
363 5
    public function getItemByObjectId($objectId)
364
    {
365 5
        $ret = false;
366 5
        $type = $this->getTypeByObjectId($objectId);
367
368 5
        if ($type !== false) {
369 5
            $numId = $this->getNumericIdByObjectId($objectId);
370 5
            if ($type == self::TYPE_PHOTO) {
371 3
                $ret = $this->getPhotoById($numId);
0 ignored issues
show
$numId is of type integer|double|false, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
372 4
            } elseif ($type == self::TYPE_VIDEO) {
373 4
                $ret = $this->getVideoById($numId);
0 ignored issues
show
$numId is of type integer|double|false, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
374
            }
375
376 5
            if (is_array($ret)) {
377 5
                $ret['type'] = $type;
378 5
                $ret['object_id'] = $objectId;
379
            }
380
        }
381
382 5
        return $ret;
383
    }
384
385
    /**
386
     * Returns all tags in the database, optionally with the items attached to each tag.
387
     *
388
     * @param bool $withItems true to attach items
389
     *
390
     * @return array tags
391
     */
392 7
    public function getAllTags($withItems = false)
393
    {
394 7
        $q = 'SELECT * FROM TagTable';
395 7
        $res = $this->db->prepare($q);
396 7
        $res->execute();
397 7
        $ret = [];
398
399 7
        while (($data = $res->fetch(\PDO::FETCH_ASSOC))) {
400 7
            if ($withItems === true) {
401 1
                $data = $this->appendItemsToTag($data);
402
            }
403 7
            $ret[] = $data;
404
        }
405
406 7
        return $ret;
407
    }
408
409
    /**
410
     * Appends items to a tag
411
     *
412
     * @param string $tag tag
413
     *
414
     * @return array the altered tag
415
     */
416 2
    private function appendItemsToTag($tag)
417
    {
418 2
        if (isset($tag['photo_id_list'])) {
419 2
            $thisItems = array_map('trim', explode(',', $tag['photo_id_list']));
420 2
            foreach ($thisItems as $objectId) {
421 2
                if (!empty($objectId) > 0) {
422 2
                    $tag['items'][] = $this->getItemByObjectId($objectId);
423
                }
424
            }
425
        }
426 2
        return $tag;
427
    }
428
429
    /**
430
     * Gets items that are linked to a given tag
431
     *
432
     * @param string $tagName name of the tag
433
     *
434
     * @return array items
435
     */
436 1
    public function getItemsByTag($tagName)
437
    {
438 1
        $tagData = $this->getTag($tagName);
439 1
        $ret = array();
440
441 1
        if (is_array($tagData) && isset($tagData['photo_id_list'])) {
442 1
            $foundItems = explode(",", $tagData['photo_id_list']);
443
444 1
            foreach ($foundItems as $item) {
445 1
                $item = trim($item);
446 1
                if (!empty($item)) {
447 1
                    $thisItem = $this->getItemByObjectId($item);
448 1
                    if (is_array($thisItem)) {
449 1
                        $ret[] = $thisItem;
450
                    }
451
                }
452
            }
453
        }
454
455 1
        return $ret;
456
    }
457
458
    /**
459
     * Gets a given tag, possibly creating it when not existent and maybe attaching the items to it.
460
     *
461
     * @param string $tagName tag name
462
     * @param bool $autoCreate shall it be auto created if it doesn't exist?
463
     * @param bool $withItems  shall items be attached to it ('items' element)
464
     *
465
     * @return array|mixed|null tag
466
     */
467 4
    public function getTag($tagName, $autoCreate = false, $withItems = false)
468
    {
469 4
        $q = 'SELECT * FROM TagTable WHERE name=?';
470 4
        $res = $this->db->prepare($q);
471 4
        $res->execute(array(
472 4
                $tagName
473
        ));
474
475 4
        $ret = null;
476 4
        $data = $res->fetch(\PDO::FETCH_ASSOC);
477
478 4
        if (is_array($data) && isset($data['id'])) {
479 4
            $ret = $data;
480 4
            if ($withItems === true) {
481 4
                $ret = $this->appendItemsToTag($ret);
0 ignored issues
show
$ret is of type array<string,?,{"id":"?"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
482
            }
483
        } else {
484
            // autocreate?
485 3
            if ($autoCreate === true) {
486 2
                $this->createTag($tagName);
487 2
                return $this->getTag($tagName, $autoCreate, $withItems);
488
            }
489
        }
490
491 4
        return $ret;
492
    }
493
494
    /**
495
     * Gets the ID from a tag name
496
     *
497
     * @param $tagName tag name
498
     *
499
     * @return bool|string either the id or false if it doesn't exist
500
     */
501 3
    public function getTagId($tagName)
502
    {
503 3
        $ret = false;
504 3
        $tagData = $this->getTag($tagName);
505
506 3
        if (isset($tagData['id'])) {
507 3
            $ret = $tagData['id'];
508
        }
509
510 3
        return $ret;
511
    }
512
513
    /**
514
     * Create a new tag
515
     *
516
     * @param string $tagName tag name
517
     *
518
     * @return bool true if all good, false otherwise
519
     */
520 3
    public function createTag($tagName)
521
    {
522 3
        $ret = false;
523
524 3
        if (is_null($this->getTag($tagName))) {
525
            $insQ = "
526
                 INSERT INTO TagTable
527
                    (`name`, `photo_id_list`, `time_created`)
528
                    VALUES (?, ?, ?)
529 3
                    ";
530 3
            $res = $this->db->prepare($insQ);
531 3
            $res->execute([$tagName, '', time()]);
532 3
            $ret = true;
533
        }
534
535 3
        return $ret;
536
    }
537
538
    /**
539
     * Gets items whose filename (whole path) matches a given string
540
     *
541
     * @param string $path any part of the filename
542
     *
543
     * @return array matching items
544
     */
545 1
    public function getItemsByPath($path)
546
    {
547 1
        return $this->searchAllWithCondition('filename', $path);
548
    }
549
550
    /**
551
     * Flexible search on the database
552
     *
553
     * @param string $field Which field
554
     * @param string $value Which value
555
     *
556
     * @return array matching items
557
     */
558 2
    private function searchAllWithCondition($field = null, $value = null)
559
    {
560 2
        if ($field != null && $field != null) {
0 ignored issues
show
It seems like you are loosely comparing $field of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
561
            $q = "
562
            SELECT id, 'video' as type FROM VideoTable
563 1
            WHERE `" . $field . "`  LIKE ?
564
            UNION ALL
565
            SELECT id, 'photo' FROM PhotoTable
566 1
            WHERE `" . $field . "` LIKE ?";
567
568 1
            $res = $this->db->prepare($q);
569 1
            $res->execute(['%' . $value . '%', '%' . $value . '%']);
570
        } else {
571
            $q = "
572
            SELECT id, 'video' as type FROM VideoTable
573
            UNION ALL
574 1
            SELECT id, 'photo' FROM PhotoTable";
575
576 1
            $res = $this->db->prepare($q);
577 1
            $res->execute([]);
578
        }
579
580 2
        $ret = array();
581
582 2
        while (($data = $res->fetch(\PDO::FETCH_ASSOC))) {
583 2
            if ($data['type'] == 'video') {
584 2
                $item = $this->getVideoById($data['id']);
585 2
                $ret[] = $item;
586
            }
587 2
            if ($data['type'] == 'photo') {
588 2
                $item = $this->getPhotoById($data['id']);
589 2
                $ret[] = $item;
590
            }
591
        }
592
593 2
        return $ret;
594
    }
595
596
    /**
597
     * Returns an array that has every item as key (Object IDs) and the value
598
     * is an array of tags associated to that item.
599
     *
600
     * @return array
601
     */
602 7
    public function getItemTagMap()
603
    {
604 7
        $tagData = $this->getAllTags();
605 7
        $ret = array();
606
607 7
        foreach ($tagData as $tag) {
608 7
            $thisItems = explode(",", $tag['photo_id_list']);
609 7
            foreach ($thisItems as $objectId) {
610 7
                if (strlen($objectId) > 0) {
611 7
                    $ret[$objectId][] = $tag['name'];
612
                }
613
            }
614
        }
615
616 7
        return $ret;
617
    }
618
619
    /**
620
     * Gets the object type (video or photo, compare with the constants) of a given Object ID
621
     *
622
     * @param string $objectId Object ID
623
     *
624
     * @return bool|int|string type
625
     */
626 5
    public function getTypeByObjectId($objectId)
627
    {
628 5
        $foundType = false;
629 5
        foreach ($this->typeMap as $intName => $idPart) {
630 5
            if (substr($objectId, 0, strlen($idPart)) == $idPart) {
631 5
                $foundType = $intName;
632 5
                break;
633
            }
634
        }
635
636 5
        return $foundType;
637
    }
638
639
    /**
640
     * Returns the Object ID with a type and a numeric ID
641
     *
642
     * @param string $type      Either photo or video, use the class constants
643
     * @param string $numericId Numeric ID
644
     *
645
     * @return string Object ID
646
     */
647 7
    public function getObjectIdByNumericId($type, $numericId)
648
    {
649 7
        $ret = $this->typeMap[$type];
650 7
        $ret .= str_pad(dechex($numericId), 16, "0", STR_PAD_LEFT);
651 7
        return $ret;
652
    }
653
654
    /**
655
     * Gets the type prefix for a given type
656
     *
657
     * @param string $type type
658
     *
659
     * @return bool|string prefix or false
660
     */
661 5
    public function getObjectIdPartIdByType($type)
662
    {
663 5
        if (isset($this->typeMap[$type])) {
664 5
            return $this->typeMap[$type];
665
        }
666
        return false;
667
    }
668
669
    /**
670
     * Returns the numeric ID of a given Object ID
671
     *
672
     * @param string $objectId Object ID
673
     *
674
     * @return bool|number|string numeric id
675
     */
676 5
    public function getNumericIdByObjectId($objectId)
677
    {
678 5
        $ret = false;
679 5
        $thisType = $this->getTypeByObjectId($objectId);
680 5
        if ($thisType !== false) {
681 5
            $ret = ltrim(
682
                substr(
683
                    $objectId,
684 5
                    strlen($this->getObjectIdPartIdByType($thisType))
685
                ),
686 5
                ' 0'
687
            );
688 5
            $ret = hexdec($ret);
689
        }
690
691 5
        return $ret;
692
    }
693
}
694