public function localize($file_id)
 {
     $contentClient = new \Guzzle\Service\Client('http://' . Config::get('app.content_host') . '/');
     $attachment = Attachment::find($file_id);
     $mailbox = Mailbox::find($attachment->mailbox_id);
     $tmpfname = tempnam(sys_get_temp_dir(), $file_id);
     $response = $this->contextIO->getFileContent($mailbox->mailbox_id, ['file_id' => $attachment->attachment_id], $tmpfname);
     if (!$response) {
         return ['success' => false, 'error_message' => 'Failed to retrieve context.io file contents'];
     }
     $sha1 = sha1_file($tmpfname);
     if (strrpos(basename($attachment->original_path), '.')) {
         $extension = substr(basename($attachment->original_path), strrpos(basename($attachment->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();
     }
     // Update the database with the file size information
     $attachment->file_sha = $sha1;
     $attachment->etag = sha1($sha1 . $attachment->bytes . $attachment->service_updated_at . $attachment->client_updated_at);
     $attachment->save();
     // TODO: Error handling
     // TODO: Process abstraction from controller to classes
     return ['success' => true, 'local_url' => 'http://' . Config::get('app.content_host') . '/' . $save_path];
 }