Passed
Push — master ( 4f783c...449b2c )
by Paul
07:14
created

Avatar::fallbackUrl()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
eloc 5
c 0
b 0
f 0
dl 0
loc 8
ccs 0
cts 6
cp 0
rs 10
cc 2
nc 2
nop 2
crap 6
1
<?php
2
3
namespace GeminiLabs\SiteReviews\Modules;
4
5
use GeminiLabs\SiteReviews\Helper;
6
use GeminiLabs\SiteReviews\Helpers\Arr;
7
use GeminiLabs\SiteReviews\Helpers\Cast;
8
use GeminiLabs\SiteReviews\Helpers\Str;
9
use GeminiLabs\SiteReviews\Modules\Html\Builder;
10
use GeminiLabs\SiteReviews\Modules\PixelAvatar;
11
use GeminiLabs\SiteReviews\Review;
12
13
class Avatar
14
{
15
    const FALLBACK_SIZE = 40;
16
    const GRAVATAR_URL = 'https://secure.gravatar.com/avatar';
17
18
    /**
19
     * @var string
20
     */
21
    public $type;
22
23 15
    public function __construct()
24
    {
25 15
        $this->type = glsr_get_option('reviews.avatars_fallback', 'mystery', 'string');
26 15
    }
27
28
    /**
29
     * @param \GeminiLabs\SiteReviews\Review $review
30
     * @return string
31
     */
32 15
    public function fallbackDefault($review)
33
    {
34 15
        if ('pixels' === $this->type) {
35
            return $this->generatePixels($review);
36
        }
37 15
        if ('initials' === $this->type) {
38
            if (!empty($review->author)) {
39
                return $this->generateInitials($review);
40
            }
41
            $this->type = 'mystery'; // can't create initials without a name
42
        }
43 15
        return $this->type;
44
    }
45
46
    /**
47
     * @param \GeminiLabs\SiteReviews\Review $review
48
     * @param int $size
49
     * @return string
50
     */
51
    public function fallbackUrl($review, $size = 0)
52
    {
53
        $fallbackUrl = $this->fallbackDefault($review);
54
        if ($fallbackUrl === $this->type) {
55
            $fallbackUrl = add_query_arg('d', $this->type, static::GRAVATAR_URL);
56
            $fallbackUrl = add_query_arg('s', $this->size($size), $fallbackUrl);
57
        }
58
        return glsr()->filterString('avatar/fallback', $fallbackUrl, $size, $review);
59
    }
60
61
    /**
62
     * @param \GeminiLabs\SiteReviews\Review $review
63
     * @param int $size
64
     * @return string
65
     */
66 15
    public function generate($review, $size = 0)
67
    {
68 15
        $default = $this->fallbackDefault($review);
69 15
        $size = $this->size($size);
70 15
        $avatarUrl = get_avatar_url($this->userField($review), [
71 15
            'default' => $default,
72 15
            'size' => $size,
73
        ]);
74 15
        if (!$this->isUrl($avatarUrl)) {
75
            return $this->fallbackUrl($review, $size);
76
        }
77 15
        if ($default !== $this->type && glsr()->filterBool('devmode', false)) {
78
            if (200 !== Helper::remoteStatusCheck($avatarUrl)) {
79
                return $this->fallbackUrl($review, $size);
80
            }
81
        }
82 15
        return $avatarUrl;
83
    }
84
85
    /**
86
     * @param \GeminiLabs\SiteReviews\Review $review
87
     * @return string
88
     */
89
    public function generateInitials($review)
90
    {
91
        $initials = Str::convertToInitials($review->author);
92
        if (mb_strlen($initials) === 1) {
93
            $initials = mb_substr(trim($review->author), 0, 2, 'UTF-8');
94
            $initials = mb_strtoupper($initials, 'UTF-8');
95
        }
96
        $contents = $this->svgContent($initials);
97
        return $this->svg($contents, $initials);
98
    }
99
100
    /**
101
     * @param \GeminiLabs\SiteReviews\Review $review
102
     * @return string
103
     */
104
    public function generatePixels($review)
105
    {
106
        $hash = md5(strtolower(trim($this->userField($review))));
107
        $hash = substr($hash, 0, 15);
108
        $contents = glsr(PixelAvatar::class)->generate($hash);
109
        return $this->svg($contents, $hash);
110
    }
111
112
    /**
113
     * @param \GeminiLabs\SiteReviews\Review $review
114
     * @param int $size
115
     * @return string
116
     */
117
    public function img($review, $size = 0)
118
    {
119
        $size = $this->size($size);
120
        $attributes = [
121
            'alt' => sprintf(__('Avatar for %s', 'site-reviews'), $review->author()),
122
            'height' => $size, // @2x
123
            'loading' => 'lazy',
124
            'src' => $this->url($review, $size), // @2x
125
            'style' => sprintf('width:%1$spx; height:%1$spx;', $size / 2), // @1x
126
            'width' => $size, // @2x
127
        ];
128
        if (glsr()->isAdmin()) {
129
            $attributes['data-fallback'] = $this->fallbackUrl($review, $size);
130
        }
131
        $attributes = glsr()->filterArray('avatar/attributes', $attributes, $review);
132
        return glsr(Builder::class)->img($attributes);
133
    }
134
135
    /**
136
     * @param \GeminiLabs\SiteReviews\Review $review
137
     * @param int $size
138
     * @return string
139
     */
140 14
    public function url($review, $size = 0)
141
    {
142 14
        if ($this->isUrl($review->avatar)) {
143 14
            return $review->avatar;
144
        }
145
        return $this->fallbackUrl($review, $size);
146
    }
147
148
    /**
149
     * @param mixed $url
150
     * @return bool
151
     */
152 15
    protected function isUrl($url)
153
    {
154 15
        return !empty(filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_PATH_REQUIRED));
155
    }
156
157
    /**
158
     * @param int $size
159
     * @return int
160
     */
161 15
    protected function size($size = 0)
162
    {
163 15
        $size = Cast::toInt($size);
164 15
        if ($size < 1) {
165 15
            $size = glsr_get_option('reviews.avatars_size', static::FALLBACK_SIZE, 'int');
166 15
            $size = Helper::ifEmpty($size, static::FALLBACK_SIZE, $strict = true);
167
        }
168 15
        return $size * 2; // @2x
169
    }
170
171
    /**
172
     * @param string $contents
173
     * @param string $name
174
     * @return string
175
     */
176
    protected function svg($contents, $name)
177
    {
178
        $uploadsDir = wp_upload_dir();
179
        $baseDir = trailingslashit($uploadsDir['basedir']);
180
        $baseUrl = trailingslashit($uploadsDir['baseurl']);
181
        $pathDir = trailingslashit(glsr()->id).trailingslashit('avatars');
182
        $filename = sprintf('%s.svg', $name);
183
        $filepath = $baseDir.$pathDir.$filename;
184
        if (!file_exists($filepath)) {
185
            wp_mkdir_p($baseDir.$pathDir);
186
            $fp = @fopen($filepath, 'wb');
187
            if (false === $fp) {
188
                return '';
189
            }
190
            mbstring_binary_safe_encoding();
191
            $dataLength = strlen($contents);
192
            $bytesWritten = fwrite($fp, $contents);
193
            reset_mbstring_encoding();
194
            fclose($fp);
195
            if ($dataLength !== $bytesWritten) {
196
                return '';
197
            }
198
            chmod($filepath, (fileperms(ABSPATH.'index.php') & 0777 | 0644));
199
        }
200
        return set_url_scheme($baseUrl.$pathDir.$filename);
201
    }
202
203
    /**
204
     * @param string $initials
205
     * @return string
206
     */
207
    protected function svgContent($initials)
208
    {
209
        $colors = [
210
            ['background' => '#e3effb', 'color' => '#134d92'], // blue
211
            ['background' => '#e1f0ee', 'color' => '#125960'], // green
212
            ['background' => '#ffeff7', 'color' => '#ba3a80'], // pink
213
            ['background' => '#fcece3', 'color' => '#a14326'], // red
214
            ['background' => '#faf7d9', 'color' => '#da9640'], // yellow
215
        ];
216
        $colors = glsr()->filterArray('avatar/colors', $colors);
217
        shuffle($colors);
218
        $color = Cast::toArray(Arr::get($colors, 0));
219
        $data = wp_parse_args($color, [
220
            'background' => '#dcdce6',
221
            'color' => '#6f6f87',
222
            'text' => $initials,
223
        ]);
224
        return trim(glsr()->build('avatar', $data));
225
    }
226
227
    /**
228
     * @param \GeminiLabs\SiteReviews\Review $review
229
     * @return int|string
230
     */
231 15
    protected function userField($review)
232
    {
233 15
        if ($review->author_id) {
234
            $value = get_the_author_meta('user_email', $review->author_id);
235
        }
236 15
        if (empty($value)) {
237 15
            $value = $review->email;
238
        }
239 15
        return glsr()->filterString('avatar/id_or_email', $value, $review->toArray());
240
    }
241
}
242