1 <?php # vim:ts=2:sw=2:et:
2 include '../inc/common.php';
4 $username = $_GET['u'];
6 $data = MTrackAuth::getUserData($username);
8 $loc = MTrackConfig::get('core', 'httpcachedir');
10 $loc = MTrackConfig::get('core', 'vardir') . '/httpcache';
16 $cache_duration = 3600; // seconds
19 if (isset($data['avatar'])) {
20 $source = $data['avatar'];
21 } else if (isset($data['email'])) {
22 $source = "http://www.gravatar.com/avatar/" .
23 md5(strtolower($data['email'])) . "?s=$size&d=wavatar";
24 } else if (preg_match('/^https?:\/\//', $username)) {
25 // Let's try a favatar!
27 function extract_favatar_link($filename, $relurl)
29 $data = file_get_contents($filename);
31 if (preg_match('@<head[^>]*>(.*)</head>@smi', $data, $M)) {
32 $data = "<html><head>" . $M[1] . "</head></html>";
34 $doc = new DomDocument;
35 if (!@$doc->loadHTML($data)) {
38 $xpath = new DomXPath($doc);
39 $links = $xpath->query(
40 '/html/head/link[@rel="shortcut icon" or @rel="icon"]');
42 if (substr($relurl, -1) != '/') {
46 foreach ($links as $link) {
47 $url = $link->getAttribute('href');
54 return $relurl . 'favicon.ico';
57 if (!preg_match('@^([a-zA-Z]+)://@', $url)) {
58 /* fixup relative links */
60 $url = substr($url, 1);
62 foreach ($xpath->query('/html/head/base') as $base) {
63 $url = $base->getAttribute('href') . $url;
65 if (!preg_match('@^([a-zA-Z]+)://@', $url)) {
66 $url = $relurl . $url;
72 list($head, $link) = cache_get_url_and_operate(
73 $username, 'extract_favatar_link', $username);
85 * Fetches the contents of the URL $source using a cache.
86 * Optionally runs a callback specified by $funcname on the
87 * data while it is under a lock (to ensure a consistent view).
88 * $funcname is passed the local cache filename as its first parameter.
89 * Any additional parameters passed to this function will be passed
90 * to $funcname as parameters after the cache filename.
93 * 0 => data from the url
94 * 1 => return value of optional funcname
97 function cache_get_url_and_operate($source, $funcname = null /* args */)
100 global $cache_duration;
102 $args = func_get_args();
103 if (count($args) > 2) {
109 $cache = $loc . "/" . md5($source);
110 array_unshift($args, $cache);
112 // cache file population, avoiding thundering herd and maintaining
113 // consistency under concurrency.
119 while ($tries-- > 0) {
120 logit("tries=$tries");
121 // Can we open the file for read?
122 $fp = @fopen($cache, 'r+b');
124 $fp = @fopen($cache, 'x+');
127 // Yes; get a lock for consistency
129 logit("got shared lock");
130 // What do we need to do?
132 if ($st['size'] == 0) {
133 // No data in the file, let's see if we can do something about that
134 logit("zero size; getting ex lock");
137 if ($st['size'] == 0) {
139 logit("zero sized; we're fixing it, reading from $source");
140 $tosend = file_get_contents($source);
141 fwrite($fp, $tosend);
143 if ($funcname !== null) {
144 $dat = call_user_func_array($funcname, $args);
148 // Someone else fixed it
149 logit("Someone else fixed it, size is now $st[size]");
150 } else if (time() - $st['mtime'] > $cache_duration) {
151 // Someone needs to re-fetch the data
152 logit("Past cache period, getting ex lock");
155 if (time() - $st['mtime'] > $cache_duration) {
157 logit("cache expired; reading from $source, truncating");
160 $tosend = file_get_contents($source);
161 logit("read " . strlen($tosend) . " from $source");
162 $x = fwrite($fp, $tosend);
163 logit("wrote $x to local cache file");
164 if ($funcname !== null) {
165 $dat = call_user_func_array($funcname, $args);
169 // Someone else fixed it
170 logit("Someone fixed it, mtime now $st[mtime]");
172 // Good to read through
173 logit("Reading through cache");
174 $tosend = stream_get_contents($fp);
175 if ($funcname !== null) {
176 $dat = call_user_func_array($funcname, $args);
180 logit("Couldn't get data, sleeping and retrying");
187 return array($tosend, $dat);
191 $hint = basename($source);
192 list($tosend, $mime) = cache_get_url_and_operate(
193 $source, 'mtrack_mime_detect', $hint);
195 logit("All is good, sending data");
197 logit("Unable to get data");
200 header("Content-Type: $mime");
201 header("Content-Disposition: inline; filename=\"$hint\"");
207 $cache = dirname(__FILE__) . "/images/default_avatar.png";
208 $mime = mtrack_mime_detect($cache, $cache);
209 header("Content-Type: $mime");
210 header("Content-Disposition: inline");