Completed
Pull Request — master (#3)
by Arthur
01:52
created

CacheManager::getThumbFilename()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace WebThumbnailer\Application;
4
5
6
use WebThumbnailer\Exception\CacheException;
7
use WebThumbnailer\Exception\IOException;
8
use WebThumbnailer\Utils\FileUtils;
9
10
/**
11
 * Class CacheManager
12
 *
13
 * Handles file caching using static methods.
14
 * There are 2 types of cache:
15
 *  - thumb: thumbnail images after being resized.
16
 *  - finder: url->thumbnail url resolution is also cached.
17
 * Cache files are organized by domains name, and have a unique name
18
 * based on their URL, max-width and max-height.
19
 *
20
 * Cache duration is defined in JSON settings.
21
 *
22
 * @package WebThumbnailer\Application
23
 */
24
class CacheManager
25
{
26
    /**
27
     * Thumbnails image cache.
28
     */
29
    const TYPE_THUMB  = 'thumb';
30
    /**
31
     * Finder cache.
32
     */
33
    const TYPE_FINDER = 'finder';
34
35
    /**
36
     * @var string Clean filename, used to clean directories periodically.
37
     */
38
    protected static $CLEAN_FILE = '.clean';
39
40
    /**
41
     * Returns the cache path according to the given type.
42
     *
43
     * @param string $type    Type of cache.
44
     * @param bool   $rebuilt Flag to tell if a rebuild tentative has been done.
45
     *
46
     * @return string Cache absolute path.
47
     *
48
     * @throws IOException Type not found.
49
     */
50
    public static function getCachePath($type, $rebuilt = false)
51
    {
52
        self::checkCacheType($type);
53
        $cache = ConfigManager::get('settings.path.cache', 'cache/');
54
        $path = FileUtils::getPath($cache, $type);
55
        if (!$path && !$rebuilt) {
56
            self::rebuildCacheFolders();
57
            return self::getCachePath($type, true);
58
        } else if (!$path) {
59
            throw new IOException('Cache folders are not writable: '. $cache);
60
        }
61
        return $path;
62
    }
63
64
    /**
65
     * Get a thumb cache file absolute path.
66
     *
67
     * @param string     $url    URL of the thumbnail (unique file per URL).
68
     * @param string     $domain Domain concerned.
69
     * @param string     $type   Type of cache.
70
     * @param int|string $width  User setting for image width.
71
     * @param int|string $height User setting for image height.
72
     * @param bool       $crop   Crop enabled or not.
73
     *
74
     * @return string Absolute file path.
75
     */
76
    public static function getCacheFilePath($url, $domain, $type, $width = 0, $height = 0, $crop = false)
77
    {
78
        self::createDomainThumbCacheFolder($domain, $type);
79
        $domainFolder = FileUtils::getPath(self::getCachePath($type), $domain);
80
        if ($type === self::TYPE_THUMB) {
81
            $suffix = $width . $height . ($crop ? '1' : '0') .'.png';
82
        } else {
83
            $suffix = $width . $height;
84
        }
85
        return $domainFolder . self::getThumbFilename($url) . $suffix;
0 ignored issues
show
Bug introduced by
Are you sure $domainFolder of type false|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

85
        return /** @scrutinizer ignore-type */ $domainFolder . self::getThumbFilename($url) . $suffix;
Loading history...
86
    }
87
88
    /**
89
     * Check whether a valid cache file exists or not.
90
     * Also check that that file is still valid.
91
     *
92
     * Support endless cache using a negative value.
93
     *
94
     * @param string $cacheFile Cache file path.
95
     * @param string $domain Domain concerned.
96
     * @param string $type   Type of cache.
97
     *
98
     * @return bool true if valid cache exists, false otherwise.
99
     */
100
    public static function isCacheValid($cacheFile, $domain, $type) {
101
        $out = false;
102
        $cacheDuration = ConfigManager::get('settings.cache_duration', 3600*24*31);
103
104
        if (is_readable($cacheFile)
105
            && ($cacheDuration < 0 || (time() - filemtime($cacheFile)) < $cacheDuration)
106
        ) {
107
            $out = true;
108
        } else {
109
            self::createDomainThumbCacheFolder($domain, $type);
110
        }
111
112
        return $out;
113
    }
114
115
    /**
116
     * Create the domains folder for thumb cache if it doesn't exists.
117
     *
118
     * @param string $domain Domain used.
119
     * @param string $type   Type of cache.
120
     */
121
    protected static function createDomainThumbCacheFolder($domain, $type)
122
    {
123
        $domainFolder = self::getCachePath($type) . $domain;
124
        if (!file_exists($domainFolder)) {
125
            mkdir($domainFolder, 0775, false);
126
            touch($domainFolder . '/' . self::$CLEAN_FILE);
127
        }
128
    }
129
130
    /**
131
     * Get the cache filename according to the given URL.
132
     * Using a sha1 hash to get unique valid filenames.
133
     *
134
     * @param string $url Thumbnail URL.
135
     *
136
     * @return string Thumb filename.
137
     */
138
    protected static function getThumbFilename($url)
139
    {
140
        return hash('sha1', $url);
141
    }
142
143
    /**
144
     * Make sure that the cache type exists.
145
     *
146
     * @param string $type Cache type.
147
     *
148
     * @throws CacheException Cache type doesn't exists.
149
     */
150
    protected static function checkCacheType($type)
151
    {
152
        if ($type != self::TYPE_THUMB && $type != self::TYPE_FINDER) {
153
            throw new CacheException('Unknown cache type '. $type);
154
        }
155
    }
156
157
    /**
158
     * Recreates cache folders just in case the user delete them.
159
     */
160
    protected static function rebuildCacheFolders()
161
    {
162
        $mainFolder = ConfigManager::get('settings.path.cache', 'cache/');
163
        if (! is_dir($mainFolder)) {
164
            mkdir($mainFolder, 0755);
165
        }
166
        if (! is_dir($mainFolder.self::TYPE_THUMB)) {
167
            mkdir($mainFolder.self::TYPE_THUMB, 0755);
168
        }
169
        if (! is_readable($mainFolder . self::TYPE_THUMB . DIRECTORY_SEPARATOR . '.gitkeep')) {
170
            touch($mainFolder . self::TYPE_THUMB . DIRECTORY_SEPARATOR . '.gitkeep');
171
        }
172
        if (! is_dir($mainFolder.self::TYPE_FINDER)) {
173
            mkdir($mainFolder . self::TYPE_FINDER, 0755);
174
        }
175
        if (! is_readable($mainFolder . self::TYPE_THUMB . DIRECTORY_SEPARATOR . '.gitkeep')) {
176
            touch($mainFolder.self::TYPE_FINDER.DIRECTORY_SEPARATOR.'.gitkeep');
177
        }
178
    }
179
}
180