json(['message' => ctrans('texts.self_update_not_available')], 403); } nlog('Test filesystem is writable'); $this->testWritable(); nlog('Clear cache directory'); $this->clearCacheDir(); nlog('copying release file'); if (copy($this->getDownloadUrl(), storage_path('app/invoiceninja.zip'))) { nlog('Copied file from URL'); } else { return response()->json(['message' => 'Download not yet available. Please try again shortly.'], 410); } nlog('Finished copying'); $file = Storage::disk('local')->path('invoiceninja.zip'); nlog('Extracting zip'); //clean up old snappdf installations //$this->cleanOldSnapChromeBinaries(); $zipFile = new \PhpZip\ZipFile(); $zipFile->openFile($file); $zipFile->extractTo(base_path()); $zipFile->close(); $zipFile = null; nlog('Finished extracting files'); unlink($file); nlog('Deleted release zip file'); foreach ($this->purge_file_list as $purge_file_path) { $purge_file = base_path($purge_file_path); if (file_exists($purge_file)) { unlink($purge_file); } } nlog('Removing cache files'); Artisan::call('clear-compiled'); Artisan::call('route:clear'); Artisan::call('view:clear'); Artisan::call('migrate', ['--force' => true]); Artisan::call('optimize'); $this->buildCache(true); nlog('Called Artisan commands'); return response()->json(['message' => 'Update completed'], 200); } private function cleanOldSnapChromeBinaries() { $current_revision = base_path('vendor/beganovich/snappdf/versions/revision.txt'); $current_revision_text = file_get_contents($current_revision); $iterator = new \DirectoryIterator(base_path('vendor/beganovich/snappdf/versions')); foreach ($iterator as $file) { if ($file->isDir() && ! $file->isDot() && ($current_revision_text != $file->getFileName())) { $directoryIterator = new \RecursiveDirectoryIterator(base_path('vendor/beganovich/snappdf/versions/'.$file->getFileName()), \RecursiveDirectoryIterator::SKIP_DOTS); foreach (new \RecursiveIteratorIterator($directoryIterator) as $filex) { unlink($filex->getPathName()); } $this->deleteDirectory(base_path('vendor/beganovich/snappdf/versions/'.$file->getFileName())); } } } private function deleteDirectory($dir) { if (! file_exists($dir)) { return true; } if (! is_dir($dir) || is_link($dir)) { return unlink($dir); } foreach (scandir($dir) as $item) { if ($item == '.' || $item == '..') { continue; } if (! $this->deleteDirectory($dir.'/'.$item)) { if (! $this->deleteDirectory($dir.'/'.$item)) { return false; } } } return rmdir($dir); } private function postHookUpdate() { if (config('ninja.app_version') == '5.3.82') { Client::withTrashed()->cursor()->each(function ($client) { $entity_settings = $this->checkSettingType($client->settings); $entity_settings->md5 = md5(time()); $client->settings = $entity_settings; $client->save(); }); } } private function clearCacheDir() { $directoryIterator = new \RecursiveDirectoryIterator(base_path('bootstrap/cache'), \RecursiveDirectoryIterator::SKIP_DOTS); foreach (new \RecursiveIteratorIterator($directoryIterator) as $file) { unlink(base_path('bootstrap/cache/').$file->getFileName()); } } private function testWritable() { $directoryIterator = new \RecursiveDirectoryIterator(base_path(), \RecursiveDirectoryIterator::SKIP_DOTS); foreach (new \RecursiveIteratorIterator($directoryIterator) as $file) { if (strpos($file->getPathname(), '.git') !== false) { continue; } if ($file->isFile() && ! $file->isWritable()) { nlog("Cannot update system because {$file->getFileName()} is not writable"); throw new FilePermissionsFailure("Cannot update system because {$file->getFileName()} is not writable"); return false; } } return true; } public function checkVersion() { return trim(file_get_contents(config('ninja.version_url'))); } private function getDownloadUrl() { $version = $this->checkVersion(); return "https://github.com/invoiceninja/invoiceninja/releases/download/v{$version}/invoiceninja.zip"; } }