php8
[web.mtrack] / MTrackWeb / Avatar.php
1 <?php # vim:ts=2:sw=2:et:
2 /* For licensing and copyright terms, see the file named LICENSE */
3
4 require_once 'MTrackWeb.php';
5
6 class MTrackWeb_Avatar extends MTrackWeb
7 {
8     var $cache_duration = 3600;
9     function getAuth()
10     {
11         return parent::getAuth();
12     }
13     
14     function get() 
15     {
16         if (empty($_GET['u']) || empty($_GET['s'])) {
17             die("invalid url");
18         }
19       
20         $size = $_GET['s'];
21         $u = DB_DataObject::factory('userinfo');
22         $u->get('userid', $_GET['u']);
23         
24         $this->cachedir = ini_get('session.save_path').'/mtrack_cache';
25         if (!file_exists($this->cachedir)) {
26             mkdir($this->cachedir, 0700,true);
27         }
28         
29         if (empty($u->avatar) && !empty($u->email))
30         {
31             $u->avatar  ="http://www.gravatar.com/avatar/" .
32                 md5(strtolower($u->email)) . "?s=$size&d=wavatar";
33         }
34         
35                 
36         if ($u->avatar ) {
37           $hint = basename($u->avatar );
38           list($tosend) = $this->cache_get_url_and_operate(  $u->avatar);
39           
40           if ($tosend) {
41             header("Content-Type: image/png");
42             header("Content-Disposition: inline; filename=\"$hint\"");
43             echo $tosend;
44             exit;
45           }
46         }
47
48         $cache = dirname(__FILE__) . "/images/default_avatar.png";
49         header('Content-Type:image/png');
50         header("Content-Disposition: inline");
51         readfile($cache);
52         exit;
53         }
54     // removed favatar option....
55
56         /**
57          * Fetches the contents of the URL $source using a cache.
58          * Optionally runs a callback specified by $funcname on the
59          * data while it is under a lock (to ensure a consistent view).
60          * $funcname is passed the local cache filename as its first parameter.
61          * Any additional parameters passed to this function will be passed
62          * to $funcname as parameters after the cache filename.
63          *
64          * returns an array(
65          *  0 => data from the url
66          *  1 => return value of optional funcname
67          * )
68          */
69     function cache_get_url_and_operate($source, $funcname = null /* args */)
70     {
71             
72
73           $args = func_get_args();
74           if (count($args) > 2) {
75             array_shift($args);
76             array_shift($args);
77           } else {
78             $args = array();
79           }
80           $cache = $this->cachedir . "/" . md5($source);
81           array_unshift($args, $cache);
82
83           // cache file population, avoiding thundering herd and maintaining
84           // consistency under concurrency.
85
86           $dat = null;
87           $tosend = null;
88
89           $tries = 20;
90           while ($tries-- > 0) {
91             //logit("tries=$tries");
92             // Can we open the file for read?
93             $fp = @fopen($cache, 'r+b');
94             if (!$fp) {
95               $fp = @fopen($cache, 'x+');
96             }
97             if ($fp) {
98               // Yes; get a lock for consistency
99               flock($fp, LOCK_SH);
100              // logit("got shared lock");
101               // What do we need to do?
102               $st = fstat($fp);
103               if ($st['size'] == 0) {
104                 // No data in the file, let's see if we can do something about that
105                 //logit("zero size; getting ex lock");
106                 flock($fp, LOCK_EX);
107                 $st = fstat($fp);
108                 if ($st['size'] == 0) {
109                   // We get to fix it
110                   //logit("zero sized; we're fixing it, reading from $source");
111                   $tosend = file_get_contents($source);
112                   fwrite($fp, $tosend);
113
114                   //if ($funcname !== null) {
115                   //  $dat = call_user_func_array($funcname, $args);
116                   //}
117                   break;
118                 }
119                 // Someone else fixed it
120                 //logit("Someone else fixed it, size is now $st[size]");
121               } else if (time() - $st['mtime'] > $this->cache_duration) {
122                 // Someone needs to re-fetch the data
123                 //logit("Past cache period, getting ex lock");
124                 flock($fp, LOCK_EX);
125                 $st = fstat($fp);
126                 if (time() - $st['mtime'] > $this->cache_duration) {
127                   // We get to fix it
128                   //logit("cache expired; reading from $source, truncating");
129                   ftruncate($fp, 0);
130                   rewind($fp);
131                   $tosend = file_get_contents($source);
132                   //logit("read " . strlen($tosend) . " from $source");
133                   $x = fwrite($fp, $tosend);
134                   //logit("wrote $x to local cache file");
135                   //if ($funcname !== null) {
136                   //  $dat = call_user_func_array($funcname, $args);
137                   //}
138                   break;
139                 }
140                 // Someone else fixed it
141                 //logit("Someone fixed it, mtime now $st[mtime]");
142               }
143               // Good to read through
144               //logit("Reading through cache");
145               $tosend = stream_get_contents($fp);
146               //if ($funcname !== null) {
147               //  $dat = call_user_func_array($funcname, $args);
148               //}
149               break;
150             }
151             //logit("Couldn't get data, sleeping and retrying");
152             usleep(100);
153           }
154           if ($fp) {
155             flock($fp, LOCK_UN);
156             fclose($fp);
157           }
158           return array($tosend, $dat);
159         }
160
161         }