get('userid', $_GET['u']); $this->cachedir = ini_get('session.save_path').'/mtrack_cache'; if (!file_exists($this->cachedir)) { mkdir($this->cachedir, 0700,true); } if (empty($u->avatar) && !empty($u->email)) { $u->avatar ="http://www.gravatar.com/avatar/" . md5(strtolower($u->email)) . "?s=$size&d=wavatar"; } if ($u->avatar ) { $hint = basename($u->avatar ); list($tosend) = $this->cache_get_url_and_operate( $u->avatar); if ($tosend) { header("Content-Type: image/png"); header("Content-Disposition: inline; filename=\"$hint\""); echo $tosend; exit; } } $cache = dirname(__FILE__) . "/images/default_avatar.png"; header('Content-Type:image/png'); header("Content-Disposition: inline"); readfile($cache); exit; } // removed favatar option.... /** * Fetches the contents of the URL $source using a cache. * Optionally runs a callback specified by $funcname on the * data while it is under a lock (to ensure a consistent view). * $funcname is passed the local cache filename as its first parameter. * Any additional parameters passed to this function will be passed * to $funcname as parameters after the cache filename. * * returns an array( * 0 => data from the url * 1 => return value of optional funcname * ) */ function cache_get_url_and_operate($source, $funcname = null /* args */) { $args = func_get_args(); if (count($args) > 2) { array_shift($args); array_shift($args); } else { $args = array(); } $cache = $this->cachedir . "/" . md5($source); array_unshift($args, $cache); // cache file population, avoiding thundering herd and maintaining // consistency under concurrency. $dat = null; $tosend = null; $tries = 20; while ($tries-- > 0) { //logit("tries=$tries"); // Can we open the file for read? $fp = @fopen($cache, 'r+b'); if (!$fp) { $fp = @fopen($cache, 'x+'); } if ($fp) { // Yes; get a lock for consistency flock($fp, LOCK_SH); // logit("got shared lock"); // What do we need to do? $st = fstat($fp); if ($st['size'] == 0) { // No data in the file, let's see if we can do something about that //logit("zero size; getting ex lock"); flock($fp, LOCK_EX); $st = fstat($fp); if ($st['size'] == 0) { // We get to fix it //logit("zero sized; we're fixing it, reading from $source"); $tosend = file_get_contents($source); fwrite($fp, $tosend); //if ($funcname !== null) { // $dat = call_user_func_array($funcname, $args); //} break; } // Someone else fixed it //logit("Someone else fixed it, size is now $st[size]"); } else if (time() - $st['mtime'] > $this->cache_duration) { // Someone needs to re-fetch the data //logit("Past cache period, getting ex lock"); flock($fp, LOCK_EX); $st = fstat($fp); if (time() - $st['mtime'] > $this->cache_duration) { // We get to fix it //logit("cache expired; reading from $source, truncating"); ftruncate($fp, 0); rewind($fp); $tosend = file_get_contents($source); //logit("read " . strlen($tosend) . " from $source"); $x = fwrite($fp, $tosend); //logit("wrote $x to local cache file"); //if ($funcname !== null) { // $dat = call_user_func_array($funcname, $args); //} break; } // Someone else fixed it //logit("Someone fixed it, mtime now $st[mtime]"); } // Good to read through //logit("Reading through cache"); $tosend = stream_get_contents($fp); //if ($funcname !== null) { // $dat = call_user_func_array($funcname, $args); //} break; } //logit("Couldn't get data, sleeping and retrying"); usleep(100); } if ($fp) { flock($fp, LOCK_UN); fclose($fp); } return array($tosend, $dat); } }