]> jfr.im git - irc/unrealircd/unrealircd-webpanel.git/blame - Classes/class-upgrade.php
Put some .htaccess in place
[irc/unrealircd/unrealircd-webpanel.git] / Classes / class-upgrade.php
CommitLineData
840c8c3e
VP
1<?php
2
3class Upgrade
4{
5 public $web_dir;
1ff0282b 6 private $temp_dir;
8fed0ffb 7 private static $temp_extracted_dir;
840c8c3e
VP
8 public static $upgrade_available;
9 public static $last_check;
10 public $error;
11 public static $latest_version;
12 function __construct()
13 {
14 global $config;
15 read_config_db();
16 if (!get_config('upgrade'))
17 {
18 $config['upgrade'] =[];
19 write_config('upgrade');
20 }
21
22 $tok = split(__DIR__, '/');
23 unset($tok[count($tok) - 1]);
24 $this->web_dir = implode('/',$tok).'/';
840c8c3e 25
1ff0282b 26 /** prepare the temp directory */
24432aab
VP
27 $temp_dir = $this->web_dir."panel_upgrade";
28 $temp_dir .= ($temp_dir[strlen($temp_dir) - 1] != '/') ? "/" : "";
8fed0ffb
VP
29 if (file_exists($temp_dir)) {
30 deleteDirectoryContents($temp_dir);
31 rmdir($temp_dir);
32 }
1ff0282b
VP
33 $mkdir = mkdir($temp_dir, 0755, true);
34
35 $this->temp_dir = $mkdir ? $temp_dir : NULL;
36 $this->error = $mkdir ? NULL : "Could not create directory: $temp_dir";
840c8c3e 37 Upgrade::$upgrade_available = false;
840c8c3e
VP
38 if ($this->error)
39 error_log($this->error);
840c8c3e
VP
40 }
41
42 /** Checks for a new upgrade */
43 function checkForNew()
44 {
45 global $config;
46 read_config_db();
24432aab
VP
47 $last_check = &$config['upgrade']['last_check'];
48 if (isset($last_check) && time() - $last_check < 300) // only check every 15 mins
49 {
50 error_log("Skipping upgrade check, checked ".time() - $last_check." seconds ago");
1ff0282b 51 return false;
24432aab
VP
52 }
53 error_log(time()." - ".$last_check." = ".time()-$last_check);
54 $apiUrl = "https://api.github.com/repos/unrealircd/unrealircd-webpanel/releases";
55 $response = file_get_contents($apiUrl, false, stream_context_create(
56 ["http" => ["method" => "GET", "header" => "User-agent: UnrealIRCd Webpanel"]]
57 ));
58
840c8c3e
VP
59 if ($response === false)
60 {
61 $this->error = "Couldn't check github.";
62 return false;
63 }
64 $data = json_decode($response, true);
65 $latest = $data[count($data) - 1];
66 $config['upgrade']['latest_version'] = $latest['tag_name'];
24432aab 67 $last_check = time();
840c8c3e
VP
68 $config['upgrade']['download_link'] = $latest['zipball_url'];
69 write_config('upgrade');
70 Upgrade::$upgrade_available = (float)$latest['tag_name'] > WEBPANEL_VERSION ? true : false;
71 }
72
73 function downloadUpgradeZip()
74 {
75 $ch = curl_init(get_config('upgrade::download_link'));
24432aab 76 $fp = fopen($this->temp_dir."unrealircd-webpanel-upgrade.zip", 'w+');
840c8c3e
VP
77
78 curl_setopt($ch, CURLOPT_FILE, $fp);
79 curl_setopt($ch, CURLOPT_TIMEOUT, 60);
80 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
81 curl_setopt($ch, CURLOPT_HTTPHEADER, [
82 'User-Agent: UnrealIRCd Webpanel',
83 ]);
84 $success = curl_exec($ch);
1ff0282b
VP
85 $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
86
24432aab 87 if ($code == "403" || $code == "404")
1ff0282b
VP
88 {
89 $this->error ="Unable to download";
90 }
840c8c3e
VP
91 curl_close($ch);
92 fclose($fp);
93
94 return $success;
95 }
1ff0282b
VP
96 function extractZip() {
97 $zip = new ZipArchive;
24432aab 98 if ($zip->open($this->temp_dir."unrealircd-webpanel-upgrade.zip") === true)
1ff0282b 99 {
24432aab 100 $zip->extractTo("$this->temp_dir");
1ff0282b 101 $zip->close();
8fed0ffb
VP
102 self::$temp_extracted_dir = findOnlyDirectory($this->temp_dir);
103 error_log(self::$temp_extracted_dir);
1ff0282b
VP
104 return true;
105 } else {
106 return false;
107 }
840c8c3e 108 }
1ff0282b 109 function cleanupOldFiles()
8fed0ffb
VP
110 {
111 foreach ($this->compareAndGetFilesToDelete() as $file)
9d686725
VP
112 {
113 unlink("$this->web_dir$file");
114 error_log("Deleting: $file");
115 }
8fed0ffb
VP
116 }
117 function compareAndGetFilesToDelete() : array
1ff0282b
VP
118 {
119 $currentFiles = $this->listFiles($this->web_dir);
8fed0ffb 120 $updateFiles = $this->listFiles(self::$temp_extracted_dir);
1ff0282b 121 $filesToDelete = array_diff($currentFiles, $updateFiles);
8fed0ffb 122 $filesToActuallyDelete = [];
24432aab 123 error_log("Comparing... Files to delete:");
1ff0282b
VP
124 foreach ($filesToDelete as $file)
125 {
8fed0ffb
VP
126 // skip the relevant directories
127 if (str_starts_with($file, "panel_upgrade/")
128 || str_starts_with($file, "vendor/")
129 || str_starts_with($file, "config/")
130 || str_starts_with($file, "data/")
131 || str_starts_with($file, "plugins/"))
132 continue;
133 $filesToActuallyDelete[] = $file;
1ff0282b 134 }
8fed0ffb 135 return $filesToActuallyDelete;
840c8c3e 136 }
1ff0282b
VP
137
138 function extractToWebdir()
139 {
7416729b 140 recurse_copy(self::$temp_extracted_dir, $this->web_dir);
1ff0282b 141 }
24432aab
VP
142
143 /**
144 * Cleans up the extracted update files
145 * @return void
146 */
147 function cleanupDownloadFiles()
148 {
8fed0ffb
VP
149 $ex_dir = self::$temp_extracted_dir ?? findOnlyDirectory($this->temp_dir);
150 deleteDirectoryContents($ex_dir);
151 rmdir($ex_dir);
24432aab
VP
152 }
153
1ff0282b
VP
154 function listFiles($dir) {
155 $files = [];
156 $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
157 foreach ($iterator as $file)
158 {
159 if ($file->isFile())
160 {
24432aab
VP
161 $f = substr($file->getPathname(), strlen($dir));
162 if ($f[0] == "/") $f = substr($f,1);
24432aab
VP
163
164 $files[] = $f;
1ff0282b 165 }
840c8c3e 166 }
1ff0282b 167 return $files;
840c8c3e 168 }
840c8c3e 169}
24432aab
VP
170
171
172function findOnlyDirectory($topDir) {
173 // Ensure the directory exists and is indeed a directory
174 if (!is_dir($topDir)) {
175 die("The specified path is not a directory.");
176 }
177
178 // Open the directory
179 $dirHandle = opendir($topDir);
180 if ($dirHandle === false) {
181 die("Unable to open directory.");
182 }
183
184 $directories = [];
185
186 // Read through the directory contents
187 while (($entry = readdir($dirHandle)) !== false) {
188 $fullPath = $topDir . DIRECTORY_SEPARATOR . $entry;
189 // Check if the entry is a directory and not . or ..
190 if (is_dir($fullPath) && $entry !== '.' && $entry !== '..') {
191 $directories[] = $fullPath;
192 }
193 }
194
195 // Close the directory handle
196 closedir($dirHandle);
197
198 // Check if there is exactly one directory
199 if (count($directories) === 1) {
200 return $directories[0];
201 } elseif (count($directories) === 0) {
202 return "No directories found after extracting. Possibly missing php-zip extention. Aborting upgrade.";
203 } else {
204 return "Multiple directories found. Previous cleanup was unsuccessful for some reason, maybe a permissions error? Aborting upgrade.";
205 }
8fed0ffb
VP
206}
207
208
209function deleteDirectoryContents($dir) {
210 error_log("Deleting directory contents at $dir");
211 if (!is_dir($dir)) {
212 echo "The provided path is not a directory.";
213 return false;
214 }
215
216 // Open the directory
217 $handle = opendir($dir);
218 if ($handle === false) {
219 echo "Failed to open the directory.";
220 return false;
221 }
222
223 // Loop through the directory contents
224 while (($item = readdir($handle)) !== false) {
225 // Skip the special entries "." and ".."
226 if ($item == "." || $item == "..") {
227 continue;
228 }
229
230 $itemPath = $dir."/".$item;
231
232 // If the item is a directory, recursively delete its contents
233 if (is_dir($itemPath)) {
234 deleteDirectoryContents($itemPath);
235 // Remove the empty directory
236 rmdir($itemPath);
237 } else {
238 // If the item is a file, delete it
239 unlink($itemPath);
240 }
241 }
242
243 // Close the directory handle
244 closedir($handle);
245
246 return true;
de8a49b2
VP
247}
248
249function recurse_copy($src, $dst) {
250 $dir = opendir($src);
251 @mkdir($dst);
252 while(false !== ( $file = readdir($dir)) )
253 if (( $file != '.' ) && ( $file != '..' ))
254 {
255 if ( is_dir($src . '/' . $file) )
256 recurse_copy($src . '/' . $file, $dst . '/' . $file);
257
258 else
259 copy($src . '/' . $file, $dst . '/' . $file);
260 }
261
262
263 closedir($dir);
7416729b 264}