1<?php
2/**
3 * Zend Framework (http://framework.zend.com/)
4 *
5 * @link      http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license   http://framework.zend.com/license/new-bsd New BSD License
8 */
9
10namespace Zend\View\Helper;
11
12use Zend\View\Exception;
13
14/**
15 * Helper for retrieving avatars from gravatar.com
16 */
17class Gravatar extends AbstractHtmlElement
18{
19    /**
20     * URL to gravatar service
21     */
22    const GRAVATAR_URL = 'http://www.gravatar.com/avatar';
23    /**
24     * Secure URL to gravatar service
25     */
26    const GRAVATAR_URL_SECURE = 'https://secure.gravatar.com/avatar';
27
28    /**
29     * Gravatar rating
30     */
31    const RATING_G  = 'g';
32    const RATING_PG = 'pg';
33    const RATING_R  = 'r';
34    const RATING_X  = 'x';
35
36    /**
37     * Default gravatar image value constants
38     */
39    const DEFAULT_404       = '404';
40    const DEFAULT_MM        = 'mm';
41    const DEFAULT_IDENTICON = 'identicon';
42    const DEFAULT_MONSTERID = 'monsterid';
43    const DEFAULT_WAVATAR   = 'wavatar';
44
45    /**
46     * Attributes for HTML image tag
47     *
48     * @var array
49     */
50    protected $attribs;
51
52    /**
53     * Email Address
54     *
55     * @var string
56     */
57    protected $email;
58
59    /**
60     * True or false if the email address passed is already an MD5 hash
61     *
62     * @var bool
63     */
64    protected $emailIsHashed;
65
66    /**
67     * Options
68     *
69     * @var array
70     */
71    protected $options = array(
72        'img_size'    => 80,
73        'default_img' => self::DEFAULT_MM,
74        'rating'      => self::RATING_G,
75        'secure'      => null,
76    );
77
78    /**
79     * Returns an avatar from gravatar's service.
80     *
81     * $options may include the following:
82     * - 'img_size' int height of img to return
83     * - 'default_img' string img to return if email address has not found
84     * - 'rating' string rating parameter for avatar
85     * - 'secure' bool load from the SSL or Non-SSL location
86     *
87     * @see    http://pl.gravatar.com/site/implement/url
88     * @see    http://pl.gravatar.com/site/implement/url More information about gravatar's service.
89     * @param  string|null $email   Email address.
90     * @param  null|array  $options Options
91     * @param  array       $attribs Attributes for image tag (title, alt etc.)
92     * @return Gravatar
93     */
94    public function __invoke($email = "", $options = array(), $attribs = array())
95    {
96        if (!empty($email)) {
97            $this->setEmail($email);
98        }
99        if (!empty($options)) {
100            $this->setOptions($options);
101        }
102        if (!empty($attribs)) {
103            $this->setAttribs($attribs);
104        }
105
106        return $this;
107    }
108
109    /**
110     * Return valid image tag
111     *
112     * @return string
113     */
114    public function __toString()
115    {
116        return $this->getImgTag();
117    }
118
119    /**
120     * Configure state
121     *
122     * @param  array $options
123     * @return Gravatar
124     */
125    public function setOptions(array $options)
126    {
127        foreach ($options as $key => $value) {
128            $method = 'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key)));
129            if (method_exists($this, $method)) {
130                $this->{$method}($value);
131            }
132        }
133
134        return $this;
135    }
136
137    /**
138     * Get avatar url (including size, rating and default image options)
139     *
140     * @return string
141     */
142    protected function getAvatarUrl()
143    {
144        $src = $this->getGravatarUrl()
145            . '/'   . ($this->emailIsHashed ? $this->getEmail() : md5($this->getEmail()))
146            . '?s=' . $this->getImgSize()
147            . '&d=' . $this->getDefaultImg()
148            . '&r=' . $this->getRating();
149        return $src;
150    }
151
152    /**
153     * Get URL to gravatar's service.
154     *
155     * @return string URL
156     */
157    protected function getGravatarUrl()
158    {
159        return ($this->getSecure() === false) ? self::GRAVATAR_URL : self::GRAVATAR_URL_SECURE;
160    }
161
162    /**
163     * Return valid image tag
164     *
165     * @return string
166     */
167    public function getImgTag()
168    {
169        $this->setSrcAttribForImg();
170        $html = '<img'
171            . $this->htmlAttribs($this->getAttribs())
172            . $this->getClosingBracket();
173
174        return $html;
175    }
176
177    /**
178     * Set attribs for image tag
179     *
180     * Warning! You shouldn't set src attrib for image tag.
181     * This attrib is overwritten in protected method setSrcAttribForImg().
182     * This method(_setSrcAttribForImg) is called in public method getImgTag().
183     *
184     * @param  array $attribs
185     * @return Gravatar
186     */
187    public function setAttribs(array $attribs)
188    {
189        $this->attribs = $attribs;
190        return $this;
191    }
192
193    /**
194     * Get attribs of image
195     *
196     * Warning!
197     * If you set src attrib, you get it, but this value will be overwritten in
198     * protected method setSrcAttribForImg(). And finally your get other src
199     * value!
200     *
201     * @return array
202     */
203    public function getAttribs()
204    {
205        return $this->attribs;
206    }
207
208    /**
209     * Set default img
210     *
211     * Can be either an absolute URL to an image, or one of the DEFAULT_* constants
212     *
213     * @link   http://pl.gravatar.com/site/implement/url More information about default image.
214     * @param  string $defaultImg
215     * @return Gravatar
216     */
217    public function setDefaultImg($defaultImg)
218    {
219        $this->options['default_img'] = urlencode($defaultImg);
220        return $this;
221    }
222
223    /**
224     * Get default img
225     *
226     * @return string
227     */
228    public function getDefaultImg()
229    {
230        return $this->options['default_img'];
231    }
232
233    /**
234     * Set email address
235     *
236     * @param  string $email
237     * @return Gravatar
238     */
239    public function setEmail($email)
240    {
241        $this->emailIsHashed = (bool) preg_match('/^[A-Za-z0-9]{32}$/', $email);
242        $this->email = strtolower(trim($email));
243        return $this;
244    }
245
246    /**
247     * Get email address
248     *
249     * @return string
250     */
251    public function getEmail()
252    {
253        return $this->email;
254    }
255
256    /**
257     * Set img size in pixels
258     *
259     * @param  int $imgSize Size of img must be between 1 and 512
260     * @return Gravatar
261     */
262    public function setImgSize($imgSize)
263    {
264        $this->options['img_size'] = (int) $imgSize;
265        return $this;
266    }
267
268    /**
269     * Get img size
270     *
271     * @return int The img size
272     */
273    public function getImgSize()
274    {
275        return $this->options['img_size'];
276    }
277
278    /**
279     *  Set rating value
280     *
281     * Must be one of the RATING_* constants
282     *
283     * @link   http://pl.gravatar.com/site/implement/url More information about rating.
284     * @param  string $rating Value for rating. Allowed values are: g, px, r,x
285     * @return Gravatar
286     * @throws Exception\DomainException
287     */
288    public function setRating($rating)
289    {
290        switch ($rating) {
291            case self::RATING_G:
292            case self::RATING_PG:
293            case self::RATING_R:
294            case self::RATING_X:
295                $this->options['rating'] = $rating;
296                break;
297            default:
298                throw new Exception\DomainException(sprintf(
299                    'The rating value "%s" is not allowed',
300                    $rating
301                ));
302        }
303
304        return $this;
305    }
306
307    /**
308     * Get rating value
309     *
310     * @return string
311     */
312    public function getRating()
313    {
314        return $this->options['rating'];
315    }
316
317    /**
318     * Load from an SSL or No-SSL location?
319     *
320     * @param  bool $flag
321     * @return Gravatar
322     */
323    public function setSecure($flag)
324    {
325        $this->options['secure'] = ($flag === null) ? null : (bool) $flag;
326        return $this;
327    }
328
329    /**
330     * Get an SSL or a No-SSL location
331     *
332     * @return bool
333     */
334    public function getSecure()
335    {
336        if ($this->options['secure'] === null) {
337            return (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off');
338        }
339
340        return $this->options['secure'];
341    }
342
343    /**
344     * Set src attrib for image.
345     *
346     * You shouldn't set an own url value!
347     * It sets value, uses protected method getAvatarUrl.
348     *
349     * If already exists, it will be overwritten.
350     *
351     * @return void
352     */
353    protected function setSrcAttribForImg()
354    {
355        $attribs        = $this->getAttribs();
356        $attribs['src'] = $this->getAvatarUrl();
357        $this->setAttribs($attribs);
358    }
359}
360