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