diff --git a/repository/equella/lib.php b/repository/equella/lib.php index afab067d02f..14afc6ec20a 100644 --- a/repository/equella/lib.php +++ b/repository/equella/lib.php @@ -122,6 +122,49 @@ class repository_equella extends repository { return $source; } + /** + * Counts the number of failed connections. + * + * If we received the connection timeout more than 3 times in a row, we don't attemt to + * connect to the server any more during this request. + * + * This function is used by {@link repository_equella::get_file_by_reference()} that + * synchronises the file size of referenced files. + * + * @param int $errno omit if we just want to know the return value, the last curl_errno otherwise + * @return bool true if we had less than 3 failed connections, false if no more connections + * attempts recommended + */ + private function connection_result($errno = null) { + static $countfailures = array(); + $sess = sesskey(); + if (!array_key_exists($sess, $countfailures)) { + $countfailures[$sess] = 0; + } + if ($errno !== null) { + if ($errno == 0) { + // reset count of failed connections + $countfailures[$sess] = 0; + } else if ($errno == 7 /*CURLE_COULDNT_CONNECT*/ || $errno == 9 /*CURLE_REMOTE_ACCESS_DENIED*/) { + // problems with server + $countfailures[$sess]++; + } + } + return ($countfailures[$sess] < 3); + } + + /** + * Decide whether or not the file should be synced + * + * @param stored_file $storedfile + * @return bool + */ + public function sync_individual_file(stored_file $storedfile) { + // if we had several unsuccessfull attempts to connect to server - do not try any more + return $this->connection_result(); + } + + /** * Download a file, this function can be overridden by subclass. {@link curl} * @@ -155,35 +198,50 @@ class repository_equella extends repository { /** * Returns information about file in this repository by reference - * {@link repository::get_file_reference()} - * {@link repository::get_file()} * + * If the file is an image we download the contents and save it in our filesystem + * so we can generate thumbnails. Otherwise we just request the file size. * Returns null if file not found or can not be accessed * * @param stdClass $reference file reference db record - * @return null|stdClass containing attribute 'filepath' + * @return stdClass|null contains one of the following: + * - 'filesize' (for non-image files or files we failed to retrieve fully because of timeout) + * - 'filepath' (for image files that we retrieived and saved) */ public function get_file_by_reference($reference) { - $ref = unserialize(base64_decode($reference->reference)); - $url = $this->appendtoken($ref->url); - - if (!$url) { + global $USER; + $ref = @unserialize(base64_decode($reference->reference)); + if (!isset($ref->url) || !($url = $this->appendtoken($ref->url))) { // Occurs when the user isn't known.. return null; } - // We use this cache to get the correct file size. - $cachedfilepath = cache_file::get($url, array('ttl' => 0)); - if ($cachedfilepath === false) { - // Cache the file. - $path = $this->get_file($url); - $cachedfilepath = cache_file::create_from_file($url, $path['path']); + $return = null; + $cookiepathname = $this->prepare_file($USER->id. '_'. uniqid('', true). '.cookie'); + $c = new curl(array('cookie' => $cookiepathname)); + if (file_extension_in_typegroup($ref->filename, 'web_image')) { + $path = $this->prepare_file(''); + $result = $c->download_one($url, null, array('filepath' => $path, 'followlocation' => true, 'timeout' => self::SYNCIMAGE_TIMEOUT)); + if ($result === true) { + $return = (object)array('filepath' => $path); } - - if ($cachedfilepath && is_readable($cachedfilepath)) { - return (object)array('filepath' => $cachedfilepath); + } else { + $result = $c->head($url, array('followlocation' => true, 'timeout' => self::SYNCFILE_TIMEOUT)); } - return null; + // Delete cookie jar. + if (file_exists($cookiepathname)) { + unlink($cookiepathname); + } + + $this->connection_result($c->get_errno()); + $curlinfo = $c->get_info(); + if ($return === null && isset($curlinfo['http_code']) && $curlinfo['http_code'] == 200 + && array_key_exists('download_content_length', $curlinfo) + && $curlinfo['download_content_length'] >= 0) { + // we received a correct header and at least can tell the file size + $return = (object)array('filesize' => $curlinfo['download_content_length']); + } + return $return; } /**