public function localize($file_id)
 {
     $contentClient = new \Guzzle\Service\Client('http://' . Config::get('app.content_host') . '/');
     $entry = Entry::find($file_id);
     if ($entry->is_dir) {
         return ['success' => false, 'error_message' => 'Cannot compute SHA1 of directory'];
     }
     $this->authenticate($entry->dropbox_id);
     $tmpfname = tempnam(sys_get_temp_dir(), $file_id);
     $fd = fopen($tmpfname, "w+");
     $meta = $this->active_client->getFile($entry->original_path, $fd);
     $sha1 = sha1_file($tmpfname);
     if (strrpos(basename($entry->original_path), '.')) {
         $extension = substr(basename($entry->original_path), strrpos(basename($entry->original_path), '.'));
     } else {
         $extension = ".extensionless";
     }
     $save_path = 'dropbox/' . $sha1 . $extension;
     // check the byte size of the cached file if it exists on the content server
     $request = $contentClient->head($save_path);
     try {
         $response = $request->send();
         $contentLength = $response->getContentLength();
     } catch (Guzzle\Http\Exception\BadResponseException $e) {
         $clientResponseException = $e->getResponse();
         $statusCode = $clientResponseException->getStatusCode();
         if ($statusCode !== 404) {
             return ['success' => false, 'error_message' => 'HEAD request from content server path ' . $save_path . ' raised http exception ' . $statusCode . "\n" . print_r($clientResponseException, true)];
         }
         $contentLength = false;
     }
     // Raise an exception if we are about to localize this file in place of another file with the same content SHA
     if ($contentLength && $contentLength > 0 && $contentLength != filesize($tmpfname)) {
         return ['success' => false, 'error_message' => "File exists on content server with same SHA but different byte count!"];
     }
     // Upload the file if it does not already exist on the content server
     if (!$contentLength) {
         $request = $contentClient->put($save_path);
         $request->getCurlOptions()->set(CURLOPT_SSL_VERIFYHOST, false);
         // for testing ONLY!
         $request->getCurlOptions()->set(CURLOPT_SSL_VERIFYPEER, false);
         // for testing ONLY!
         // TODO: Determine which approach is best of these two:
         // Having a second pointer on same file, while first pointer is still open
         // (Temp files are deleted as soon as fclose called)
         $request->setBody(fopen($tmpfname, 'r'));
         // Or should we use....
         // rewind($fd);
         // $request->setBody($fd);
         // I'm not sure if guzzle would support that,
         // nor if w+ mode supports rewind
         // (Will it read from start without erasing after a rewind in w+?)
         $response = $request->send();
     }
     // Close the temp file pointer
     fclose($fd);
     // Update the database with the file size information
     $entry->file_sha = $sha1;
     $entry->etag = sha1($sha1 . $entry->bytes . $entry->service_updated_at . $entry->client_updated_at);
     $entry->save();
     // TODO: Error handling
     // TODO: Process abstraction from controller to classes
     return ['success' => true, 'local_url' => 'http://' . Config::get('app.content_host') . '/' . $save_path];
 }