@@ -34,199 +34,199 @@ |
||
34 | 34 | use OCP\ILogger; |
35 | 35 | |
36 | 36 | class ZIP extends Archive{ |
37 | - /** |
|
38 | - * @var \ZipArchive zip |
|
39 | - */ |
|
40 | - private $zip=null; |
|
41 | - private $path; |
|
37 | + /** |
|
38 | + * @var \ZipArchive zip |
|
39 | + */ |
|
40 | + private $zip=null; |
|
41 | + private $path; |
|
42 | 42 | |
43 | - /** |
|
44 | - * @param string $source |
|
45 | - */ |
|
46 | - public function __construct($source) { |
|
47 | - $this->path=$source; |
|
48 | - $this->zip=new \ZipArchive(); |
|
49 | - if($this->zip->open($source, \ZipArchive::CREATE)) { |
|
50 | - }else{ |
|
51 | - \OCP\Util::writeLog('files_archive', 'Error while opening archive '.$source, ILogger::WARN); |
|
52 | - } |
|
53 | - } |
|
54 | - /** |
|
55 | - * add an empty folder to the archive |
|
56 | - * @param string $path |
|
57 | - * @return bool |
|
58 | - */ |
|
59 | - public function addFolder($path) { |
|
60 | - return $this->zip->addEmptyDir($path); |
|
61 | - } |
|
62 | - /** |
|
63 | - * add a file to the archive |
|
64 | - * @param string $path |
|
65 | - * @param string $source either a local file or string data |
|
66 | - * @return bool |
|
67 | - */ |
|
68 | - public function addFile($path, $source='') { |
|
69 | - if($source and $source[0]=='/' and file_exists($source)) { |
|
70 | - $result=$this->zip->addFile($source, $path); |
|
71 | - }else{ |
|
72 | - $result=$this->zip->addFromString($path, $source); |
|
73 | - } |
|
74 | - if($result) { |
|
75 | - $this->zip->close();//close and reopen to save the zip |
|
76 | - $this->zip->open($this->path); |
|
77 | - } |
|
78 | - return $result; |
|
79 | - } |
|
80 | - /** |
|
81 | - * rename a file or folder in the archive |
|
82 | - * @param string $source |
|
83 | - * @param string $dest |
|
84 | - * @return boolean|null |
|
85 | - */ |
|
86 | - public function rename($source, $dest) { |
|
87 | - $source=$this->stripPath($source); |
|
88 | - $dest=$this->stripPath($dest); |
|
89 | - $this->zip->renameName($source, $dest); |
|
90 | - } |
|
91 | - /** |
|
92 | - * get the uncompressed size of a file in the archive |
|
93 | - * @param string $path |
|
94 | - * @return int |
|
95 | - */ |
|
96 | - public function filesize($path) { |
|
97 | - $stat=$this->zip->statName($path); |
|
98 | - return $stat['size']; |
|
99 | - } |
|
100 | - /** |
|
101 | - * get the last modified time of a file in the archive |
|
102 | - * @param string $path |
|
103 | - * @return int |
|
104 | - */ |
|
105 | - public function mtime($path) { |
|
106 | - return filemtime($this->path); |
|
107 | - } |
|
108 | - /** |
|
109 | - * get the files in a folder |
|
110 | - * @param string $path |
|
111 | - * @return array |
|
112 | - */ |
|
113 | - public function getFolder($path) { |
|
114 | - $files=$this->getFiles(); |
|
115 | - $folderContent=array(); |
|
116 | - $pathLength=strlen($path); |
|
117 | - foreach($files as $file) { |
|
118 | - if(substr($file, 0, $pathLength)==$path and $file!=$path) { |
|
119 | - if(strrpos(substr($file, 0, -1), '/')<=$pathLength) { |
|
120 | - $folderContent[]=substr($file, $pathLength); |
|
121 | - } |
|
122 | - } |
|
123 | - } |
|
124 | - return $folderContent; |
|
125 | - } |
|
126 | - /** |
|
127 | - * get all files in the archive |
|
128 | - * @return array |
|
129 | - */ |
|
130 | - public function getFiles() { |
|
131 | - $fileCount=$this->zip->numFiles; |
|
132 | - $files=array(); |
|
133 | - for($i=0;$i<$fileCount;$i++) { |
|
134 | - $files[]=$this->zip->getNameIndex($i); |
|
135 | - } |
|
136 | - return $files; |
|
137 | - } |
|
138 | - /** |
|
139 | - * get the content of a file |
|
140 | - * @param string $path |
|
141 | - * @return string |
|
142 | - */ |
|
143 | - public function getFile($path) { |
|
144 | - return $this->zip->getFromName($path); |
|
145 | - } |
|
146 | - /** |
|
147 | - * extract a single file from the archive |
|
148 | - * @param string $path |
|
149 | - * @param string $dest |
|
150 | - * @return boolean|null |
|
151 | - */ |
|
152 | - public function extractFile($path, $dest) { |
|
153 | - $fp = $this->zip->getStream($path); |
|
154 | - file_put_contents($dest, $fp); |
|
155 | - } |
|
156 | - /** |
|
157 | - * extract the archive |
|
158 | - * @param string $dest |
|
159 | - * @return bool |
|
160 | - */ |
|
161 | - public function extract($dest) { |
|
162 | - return $this->zip->extractTo($dest); |
|
163 | - } |
|
164 | - /** |
|
165 | - * check if a file or folder exists in the archive |
|
166 | - * @param string $path |
|
167 | - * @return bool |
|
168 | - */ |
|
169 | - public function fileExists($path) { |
|
170 | - return ($this->zip->locateName($path)!==false) or ($this->zip->locateName($path.'/')!==false); |
|
171 | - } |
|
172 | - /** |
|
173 | - * remove a file or folder from the archive |
|
174 | - * @param string $path |
|
175 | - * @return bool |
|
176 | - */ |
|
177 | - public function remove($path) { |
|
178 | - if($this->fileExists($path.'/')) { |
|
179 | - return $this->zip->deleteName($path.'/'); |
|
180 | - }else{ |
|
181 | - return $this->zip->deleteName($path); |
|
182 | - } |
|
183 | - } |
|
184 | - /** |
|
185 | - * get a file handler |
|
186 | - * @param string $path |
|
187 | - * @param string $mode |
|
188 | - * @return resource |
|
189 | - */ |
|
190 | - public function getStream($path, $mode) { |
|
191 | - if($mode=='r' or $mode=='rb') { |
|
192 | - return $this->zip->getStream($path); |
|
193 | - } else { |
|
194 | - //since we can't directly get a writable stream, |
|
195 | - //make a temp copy of the file and put it back |
|
196 | - //in the archive when the stream is closed |
|
197 | - if(strrpos($path, '.')!==false) { |
|
198 | - $ext=substr($path, strrpos($path, '.')); |
|
199 | - }else{ |
|
200 | - $ext=''; |
|
201 | - } |
|
202 | - $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext); |
|
203 | - if($this->fileExists($path)) { |
|
204 | - $this->extractFile($path, $tmpFile); |
|
205 | - } |
|
206 | - $handle = fopen($tmpFile, $mode); |
|
207 | - return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) { |
|
208 | - $this->writeBack($tmpFile, $path); |
|
209 | - }); |
|
210 | - } |
|
211 | - } |
|
43 | + /** |
|
44 | + * @param string $source |
|
45 | + */ |
|
46 | + public function __construct($source) { |
|
47 | + $this->path=$source; |
|
48 | + $this->zip=new \ZipArchive(); |
|
49 | + if($this->zip->open($source, \ZipArchive::CREATE)) { |
|
50 | + }else{ |
|
51 | + \OCP\Util::writeLog('files_archive', 'Error while opening archive '.$source, ILogger::WARN); |
|
52 | + } |
|
53 | + } |
|
54 | + /** |
|
55 | + * add an empty folder to the archive |
|
56 | + * @param string $path |
|
57 | + * @return bool |
|
58 | + */ |
|
59 | + public function addFolder($path) { |
|
60 | + return $this->zip->addEmptyDir($path); |
|
61 | + } |
|
62 | + /** |
|
63 | + * add a file to the archive |
|
64 | + * @param string $path |
|
65 | + * @param string $source either a local file or string data |
|
66 | + * @return bool |
|
67 | + */ |
|
68 | + public function addFile($path, $source='') { |
|
69 | + if($source and $source[0]=='/' and file_exists($source)) { |
|
70 | + $result=$this->zip->addFile($source, $path); |
|
71 | + }else{ |
|
72 | + $result=$this->zip->addFromString($path, $source); |
|
73 | + } |
|
74 | + if($result) { |
|
75 | + $this->zip->close();//close and reopen to save the zip |
|
76 | + $this->zip->open($this->path); |
|
77 | + } |
|
78 | + return $result; |
|
79 | + } |
|
80 | + /** |
|
81 | + * rename a file or folder in the archive |
|
82 | + * @param string $source |
|
83 | + * @param string $dest |
|
84 | + * @return boolean|null |
|
85 | + */ |
|
86 | + public function rename($source, $dest) { |
|
87 | + $source=$this->stripPath($source); |
|
88 | + $dest=$this->stripPath($dest); |
|
89 | + $this->zip->renameName($source, $dest); |
|
90 | + } |
|
91 | + /** |
|
92 | + * get the uncompressed size of a file in the archive |
|
93 | + * @param string $path |
|
94 | + * @return int |
|
95 | + */ |
|
96 | + public function filesize($path) { |
|
97 | + $stat=$this->zip->statName($path); |
|
98 | + return $stat['size']; |
|
99 | + } |
|
100 | + /** |
|
101 | + * get the last modified time of a file in the archive |
|
102 | + * @param string $path |
|
103 | + * @return int |
|
104 | + */ |
|
105 | + public function mtime($path) { |
|
106 | + return filemtime($this->path); |
|
107 | + } |
|
108 | + /** |
|
109 | + * get the files in a folder |
|
110 | + * @param string $path |
|
111 | + * @return array |
|
112 | + */ |
|
113 | + public function getFolder($path) { |
|
114 | + $files=$this->getFiles(); |
|
115 | + $folderContent=array(); |
|
116 | + $pathLength=strlen($path); |
|
117 | + foreach($files as $file) { |
|
118 | + if(substr($file, 0, $pathLength)==$path and $file!=$path) { |
|
119 | + if(strrpos(substr($file, 0, -1), '/')<=$pathLength) { |
|
120 | + $folderContent[]=substr($file, $pathLength); |
|
121 | + } |
|
122 | + } |
|
123 | + } |
|
124 | + return $folderContent; |
|
125 | + } |
|
126 | + /** |
|
127 | + * get all files in the archive |
|
128 | + * @return array |
|
129 | + */ |
|
130 | + public function getFiles() { |
|
131 | + $fileCount=$this->zip->numFiles; |
|
132 | + $files=array(); |
|
133 | + for($i=0;$i<$fileCount;$i++) { |
|
134 | + $files[]=$this->zip->getNameIndex($i); |
|
135 | + } |
|
136 | + return $files; |
|
137 | + } |
|
138 | + /** |
|
139 | + * get the content of a file |
|
140 | + * @param string $path |
|
141 | + * @return string |
|
142 | + */ |
|
143 | + public function getFile($path) { |
|
144 | + return $this->zip->getFromName($path); |
|
145 | + } |
|
146 | + /** |
|
147 | + * extract a single file from the archive |
|
148 | + * @param string $path |
|
149 | + * @param string $dest |
|
150 | + * @return boolean|null |
|
151 | + */ |
|
152 | + public function extractFile($path, $dest) { |
|
153 | + $fp = $this->zip->getStream($path); |
|
154 | + file_put_contents($dest, $fp); |
|
155 | + } |
|
156 | + /** |
|
157 | + * extract the archive |
|
158 | + * @param string $dest |
|
159 | + * @return bool |
|
160 | + */ |
|
161 | + public function extract($dest) { |
|
162 | + return $this->zip->extractTo($dest); |
|
163 | + } |
|
164 | + /** |
|
165 | + * check if a file or folder exists in the archive |
|
166 | + * @param string $path |
|
167 | + * @return bool |
|
168 | + */ |
|
169 | + public function fileExists($path) { |
|
170 | + return ($this->zip->locateName($path)!==false) or ($this->zip->locateName($path.'/')!==false); |
|
171 | + } |
|
172 | + /** |
|
173 | + * remove a file or folder from the archive |
|
174 | + * @param string $path |
|
175 | + * @return bool |
|
176 | + */ |
|
177 | + public function remove($path) { |
|
178 | + if($this->fileExists($path.'/')) { |
|
179 | + return $this->zip->deleteName($path.'/'); |
|
180 | + }else{ |
|
181 | + return $this->zip->deleteName($path); |
|
182 | + } |
|
183 | + } |
|
184 | + /** |
|
185 | + * get a file handler |
|
186 | + * @param string $path |
|
187 | + * @param string $mode |
|
188 | + * @return resource |
|
189 | + */ |
|
190 | + public function getStream($path, $mode) { |
|
191 | + if($mode=='r' or $mode=='rb') { |
|
192 | + return $this->zip->getStream($path); |
|
193 | + } else { |
|
194 | + //since we can't directly get a writable stream, |
|
195 | + //make a temp copy of the file and put it back |
|
196 | + //in the archive when the stream is closed |
|
197 | + if(strrpos($path, '.')!==false) { |
|
198 | + $ext=substr($path, strrpos($path, '.')); |
|
199 | + }else{ |
|
200 | + $ext=''; |
|
201 | + } |
|
202 | + $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext); |
|
203 | + if($this->fileExists($path)) { |
|
204 | + $this->extractFile($path, $tmpFile); |
|
205 | + } |
|
206 | + $handle = fopen($tmpFile, $mode); |
|
207 | + return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) { |
|
208 | + $this->writeBack($tmpFile, $path); |
|
209 | + }); |
|
210 | + } |
|
211 | + } |
|
212 | 212 | |
213 | - /** |
|
214 | - * write back temporary files |
|
215 | - */ |
|
216 | - public function writeBack($tmpFile, $path) { |
|
217 | - $this->addFile($path, $tmpFile); |
|
218 | - unlink($tmpFile); |
|
219 | - } |
|
213 | + /** |
|
214 | + * write back temporary files |
|
215 | + */ |
|
216 | + public function writeBack($tmpFile, $path) { |
|
217 | + $this->addFile($path, $tmpFile); |
|
218 | + unlink($tmpFile); |
|
219 | + } |
|
220 | 220 | |
221 | - /** |
|
222 | - * @param string $path |
|
223 | - * @return string |
|
224 | - */ |
|
225 | - private function stripPath($path) { |
|
226 | - if(!$path || $path[0]=='/') { |
|
227 | - return substr($path, 1); |
|
228 | - }else{ |
|
229 | - return $path; |
|
230 | - } |
|
231 | - } |
|
221 | + /** |
|
222 | + * @param string $path |
|
223 | + * @return string |
|
224 | + */ |
|
225 | + private function stripPath($path) { |
|
226 | + if(!$path || $path[0]=='/') { |
|
227 | + return substr($path, 1); |
|
228 | + }else{ |
|
229 | + return $path; |
|
230 | + } |
|
231 | + } |
|
232 | 232 | } |
@@ -33,21 +33,21 @@ discard block |
||
33 | 33 | use Icewind\Streams\CallbackWrapper; |
34 | 34 | use OCP\ILogger; |
35 | 35 | |
36 | -class ZIP extends Archive{ |
|
36 | +class ZIP extends Archive { |
|
37 | 37 | /** |
38 | 38 | * @var \ZipArchive zip |
39 | 39 | */ |
40 | - private $zip=null; |
|
40 | + private $zip = null; |
|
41 | 41 | private $path; |
42 | 42 | |
43 | 43 | /** |
44 | 44 | * @param string $source |
45 | 45 | */ |
46 | 46 | public function __construct($source) { |
47 | - $this->path=$source; |
|
48 | - $this->zip=new \ZipArchive(); |
|
49 | - if($this->zip->open($source, \ZipArchive::CREATE)) { |
|
50 | - }else{ |
|
47 | + $this->path = $source; |
|
48 | + $this->zip = new \ZipArchive(); |
|
49 | + if ($this->zip->open($source, \ZipArchive::CREATE)) { |
|
50 | + } else { |
|
51 | 51 | \OCP\Util::writeLog('files_archive', 'Error while opening archive '.$source, ILogger::WARN); |
52 | 52 | } |
53 | 53 | } |
@@ -65,14 +65,14 @@ discard block |
||
65 | 65 | * @param string $source either a local file or string data |
66 | 66 | * @return bool |
67 | 67 | */ |
68 | - public function addFile($path, $source='') { |
|
69 | - if($source and $source[0]=='/' and file_exists($source)) { |
|
70 | - $result=$this->zip->addFile($source, $path); |
|
71 | - }else{ |
|
72 | - $result=$this->zip->addFromString($path, $source); |
|
68 | + public function addFile($path, $source = '') { |
|
69 | + if ($source and $source[0] == '/' and file_exists($source)) { |
|
70 | + $result = $this->zip->addFile($source, $path); |
|
71 | + } else { |
|
72 | + $result = $this->zip->addFromString($path, $source); |
|
73 | 73 | } |
74 | - if($result) { |
|
75 | - $this->zip->close();//close and reopen to save the zip |
|
74 | + if ($result) { |
|
75 | + $this->zip->close(); //close and reopen to save the zip |
|
76 | 76 | $this->zip->open($this->path); |
77 | 77 | } |
78 | 78 | return $result; |
@@ -84,8 +84,8 @@ discard block |
||
84 | 84 | * @return boolean|null |
85 | 85 | */ |
86 | 86 | public function rename($source, $dest) { |
87 | - $source=$this->stripPath($source); |
|
88 | - $dest=$this->stripPath($dest); |
|
87 | + $source = $this->stripPath($source); |
|
88 | + $dest = $this->stripPath($dest); |
|
89 | 89 | $this->zip->renameName($source, $dest); |
90 | 90 | } |
91 | 91 | /** |
@@ -94,7 +94,7 @@ discard block |
||
94 | 94 | * @return int |
95 | 95 | */ |
96 | 96 | public function filesize($path) { |
97 | - $stat=$this->zip->statName($path); |
|
97 | + $stat = $this->zip->statName($path); |
|
98 | 98 | return $stat['size']; |
99 | 99 | } |
100 | 100 | /** |
@@ -111,13 +111,13 @@ discard block |
||
111 | 111 | * @return array |
112 | 112 | */ |
113 | 113 | public function getFolder($path) { |
114 | - $files=$this->getFiles(); |
|
115 | - $folderContent=array(); |
|
116 | - $pathLength=strlen($path); |
|
117 | - foreach($files as $file) { |
|
118 | - if(substr($file, 0, $pathLength)==$path and $file!=$path) { |
|
119 | - if(strrpos(substr($file, 0, -1), '/')<=$pathLength) { |
|
120 | - $folderContent[]=substr($file, $pathLength); |
|
114 | + $files = $this->getFiles(); |
|
115 | + $folderContent = array(); |
|
116 | + $pathLength = strlen($path); |
|
117 | + foreach ($files as $file) { |
|
118 | + if (substr($file, 0, $pathLength) == $path and $file != $path) { |
|
119 | + if (strrpos(substr($file, 0, -1), '/') <= $pathLength) { |
|
120 | + $folderContent[] = substr($file, $pathLength); |
|
121 | 121 | } |
122 | 122 | } |
123 | 123 | } |
@@ -128,10 +128,10 @@ discard block |
||
128 | 128 | * @return array |
129 | 129 | */ |
130 | 130 | public function getFiles() { |
131 | - $fileCount=$this->zip->numFiles; |
|
132 | - $files=array(); |
|
133 | - for($i=0;$i<$fileCount;$i++) { |
|
134 | - $files[]=$this->zip->getNameIndex($i); |
|
131 | + $fileCount = $this->zip->numFiles; |
|
132 | + $files = array(); |
|
133 | + for ($i = 0; $i < $fileCount; $i++) { |
|
134 | + $files[] = $this->zip->getNameIndex($i); |
|
135 | 135 | } |
136 | 136 | return $files; |
137 | 137 | } |
@@ -167,7 +167,7 @@ discard block |
||
167 | 167 | * @return bool |
168 | 168 | */ |
169 | 169 | public function fileExists($path) { |
170 | - return ($this->zip->locateName($path)!==false) or ($this->zip->locateName($path.'/')!==false); |
|
170 | + return ($this->zip->locateName($path) !== false) or ($this->zip->locateName($path.'/') !== false); |
|
171 | 171 | } |
172 | 172 | /** |
173 | 173 | * remove a file or folder from the archive |
@@ -175,9 +175,9 @@ discard block |
||
175 | 175 | * @return bool |
176 | 176 | */ |
177 | 177 | public function remove($path) { |
178 | - if($this->fileExists($path.'/')) { |
|
178 | + if ($this->fileExists($path.'/')) { |
|
179 | 179 | return $this->zip->deleteName($path.'/'); |
180 | - }else{ |
|
180 | + } else { |
|
181 | 181 | return $this->zip->deleteName($path); |
182 | 182 | } |
183 | 183 | } |
@@ -188,23 +188,23 @@ discard block |
||
188 | 188 | * @return resource |
189 | 189 | */ |
190 | 190 | public function getStream($path, $mode) { |
191 | - if($mode=='r' or $mode=='rb') { |
|
191 | + if ($mode == 'r' or $mode == 'rb') { |
|
192 | 192 | return $this->zip->getStream($path); |
193 | 193 | } else { |
194 | 194 | //since we can't directly get a writable stream, |
195 | 195 | //make a temp copy of the file and put it back |
196 | 196 | //in the archive when the stream is closed |
197 | - if(strrpos($path, '.')!==false) { |
|
198 | - $ext=substr($path, strrpos($path, '.')); |
|
199 | - }else{ |
|
200 | - $ext=''; |
|
197 | + if (strrpos($path, '.') !== false) { |
|
198 | + $ext = substr($path, strrpos($path, '.')); |
|
199 | + } else { |
|
200 | + $ext = ''; |
|
201 | 201 | } |
202 | 202 | $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext); |
203 | - if($this->fileExists($path)) { |
|
203 | + if ($this->fileExists($path)) { |
|
204 | 204 | $this->extractFile($path, $tmpFile); |
205 | 205 | } |
206 | 206 | $handle = fopen($tmpFile, $mode); |
207 | - return CallbackWrapper::wrap($handle, null, null, function () use ($path, $tmpFile) { |
|
207 | + return CallbackWrapper::wrap($handle, null, null, function() use ($path, $tmpFile) { |
|
208 | 208 | $this->writeBack($tmpFile, $path); |
209 | 209 | }); |
210 | 210 | } |
@@ -223,9 +223,9 @@ discard block |
||
223 | 223 | * @return string |
224 | 224 | */ |
225 | 225 | private function stripPath($path) { |
226 | - if(!$path || $path[0]=='/') { |
|
226 | + if (!$path || $path[0] == '/') { |
|
227 | 227 | return substr($path, 1); |
228 | - }else{ |
|
228 | + } else { |
|
229 | 229 | return $path; |
230 | 230 | } |
231 | 231 | } |
@@ -47,7 +47,7 @@ discard block |
||
47 | 47 | $this->path=$source; |
48 | 48 | $this->zip=new \ZipArchive(); |
49 | 49 | if($this->zip->open($source, \ZipArchive::CREATE)) { |
50 | - }else{ |
|
50 | + } else{ |
|
51 | 51 | \OCP\Util::writeLog('files_archive', 'Error while opening archive '.$source, ILogger::WARN); |
52 | 52 | } |
53 | 53 | } |
@@ -68,7 +68,7 @@ discard block |
||
68 | 68 | public function addFile($path, $source='') { |
69 | 69 | if($source and $source[0]=='/' and file_exists($source)) { |
70 | 70 | $result=$this->zip->addFile($source, $path); |
71 | - }else{ |
|
71 | + } else{ |
|
72 | 72 | $result=$this->zip->addFromString($path, $source); |
73 | 73 | } |
74 | 74 | if($result) { |
@@ -177,7 +177,7 @@ discard block |
||
177 | 177 | public function remove($path) { |
178 | 178 | if($this->fileExists($path.'/')) { |
179 | 179 | return $this->zip->deleteName($path.'/'); |
180 | - }else{ |
|
180 | + } else{ |
|
181 | 181 | return $this->zip->deleteName($path); |
182 | 182 | } |
183 | 183 | } |
@@ -196,7 +196,7 @@ discard block |
||
196 | 196 | //in the archive when the stream is closed |
197 | 197 | if(strrpos($path, '.')!==false) { |
198 | 198 | $ext=substr($path, strrpos($path, '.')); |
199 | - }else{ |
|
199 | + } else{ |
|
200 | 200 | $ext=''; |
201 | 201 | } |
202 | 202 | $tmpFile = \OC::$server->getTempManager()->getTemporaryFile($ext); |
@@ -225,7 +225,7 @@ discard block |
||
225 | 225 | private function stripPath($path) { |
226 | 226 | if(!$path || $path[0]=='/') { |
227 | 227 | return substr($path, 1); |
228 | - }else{ |
|
228 | + } else{ |
|
229 | 229 | return $path; |
230 | 230 | } |
231 | 231 | } |
@@ -30,113 +30,113 @@ |
||
30 | 30 | use OCP\ILogger; |
31 | 31 | |
32 | 32 | class NaturalSort { |
33 | - private static $instance; |
|
34 | - private $collator; |
|
35 | - private $cache = array(); |
|
33 | + private static $instance; |
|
34 | + private $collator; |
|
35 | + private $cache = array(); |
|
36 | 36 | |
37 | - /** |
|
38 | - * Instantiate a new \OC\NaturalSort instance. |
|
39 | - * @param object $injectedCollator |
|
40 | - */ |
|
41 | - public function __construct($injectedCollator = null) { |
|
42 | - // inject an instance of \Collator('en_US') to force using the php5-intl Collator |
|
43 | - // or inject an instance of \OC\NaturalSort_DefaultCollator to force using Owncloud's default collator |
|
44 | - if (isset($injectedCollator)) { |
|
45 | - $this->collator = $injectedCollator; |
|
46 | - \OCP\Util::writeLog('core', 'forced use of '.get_class($injectedCollator), ILogger::DEBUG); |
|
47 | - } |
|
48 | - } |
|
37 | + /** |
|
38 | + * Instantiate a new \OC\NaturalSort instance. |
|
39 | + * @param object $injectedCollator |
|
40 | + */ |
|
41 | + public function __construct($injectedCollator = null) { |
|
42 | + // inject an instance of \Collator('en_US') to force using the php5-intl Collator |
|
43 | + // or inject an instance of \OC\NaturalSort_DefaultCollator to force using Owncloud's default collator |
|
44 | + if (isset($injectedCollator)) { |
|
45 | + $this->collator = $injectedCollator; |
|
46 | + \OCP\Util::writeLog('core', 'forced use of '.get_class($injectedCollator), ILogger::DEBUG); |
|
47 | + } |
|
48 | + } |
|
49 | 49 | |
50 | - /** |
|
51 | - * Split the given string in chunks of numbers and strings |
|
52 | - * @param string $t string |
|
53 | - * @return array of strings and number chunks |
|
54 | - */ |
|
55 | - private function naturalSortChunkify($t) { |
|
56 | - // Adapted and ported to PHP from |
|
57 | - // http://my.opera.com/GreyWyvern/blog/show.dml/1671288 |
|
58 | - if (isset($this->cache[$t])) { |
|
59 | - return $this->cache[$t]; |
|
60 | - } |
|
61 | - $tz = array(); |
|
62 | - $x = 0; |
|
63 | - $y = -1; |
|
64 | - $n = null; |
|
50 | + /** |
|
51 | + * Split the given string in chunks of numbers and strings |
|
52 | + * @param string $t string |
|
53 | + * @return array of strings and number chunks |
|
54 | + */ |
|
55 | + private function naturalSortChunkify($t) { |
|
56 | + // Adapted and ported to PHP from |
|
57 | + // http://my.opera.com/GreyWyvern/blog/show.dml/1671288 |
|
58 | + if (isset($this->cache[$t])) { |
|
59 | + return $this->cache[$t]; |
|
60 | + } |
|
61 | + $tz = array(); |
|
62 | + $x = 0; |
|
63 | + $y = -1; |
|
64 | + $n = null; |
|
65 | 65 | |
66 | - while (isset($t[$x])) { |
|
67 | - $c = $t[$x]; |
|
68 | - // only include the dot in strings |
|
69 | - $m = ((!$n && $c === '.') || ($c >= '0' && $c <= '9')); |
|
70 | - if ($m !== $n) { |
|
71 | - // next chunk |
|
72 | - $y++; |
|
73 | - $tz[$y] = ''; |
|
74 | - $n = $m; |
|
75 | - } |
|
76 | - $tz[$y] .= $c; |
|
77 | - $x++; |
|
78 | - } |
|
79 | - $this->cache[$t] = $tz; |
|
80 | - return $tz; |
|
81 | - } |
|
66 | + while (isset($t[$x])) { |
|
67 | + $c = $t[$x]; |
|
68 | + // only include the dot in strings |
|
69 | + $m = ((!$n && $c === '.') || ($c >= '0' && $c <= '9')); |
|
70 | + if ($m !== $n) { |
|
71 | + // next chunk |
|
72 | + $y++; |
|
73 | + $tz[$y] = ''; |
|
74 | + $n = $m; |
|
75 | + } |
|
76 | + $tz[$y] .= $c; |
|
77 | + $x++; |
|
78 | + } |
|
79 | + $this->cache[$t] = $tz; |
|
80 | + return $tz; |
|
81 | + } |
|
82 | 82 | |
83 | - /** |
|
84 | - * Returns the string collator |
|
85 | - * @return \Collator string collator |
|
86 | - */ |
|
87 | - private function getCollator() { |
|
88 | - if (!isset($this->collator)) { |
|
89 | - // looks like the default is en_US_POSIX which yields wrong sorting with |
|
90 | - // German umlauts, so using en_US instead |
|
91 | - if (class_exists('Collator')) { |
|
92 | - $this->collator = new \Collator('en_US'); |
|
93 | - } |
|
94 | - else { |
|
95 | - $this->collator = new \OC\NaturalSort_DefaultCollator(); |
|
96 | - } |
|
97 | - } |
|
98 | - return $this->collator; |
|
99 | - } |
|
83 | + /** |
|
84 | + * Returns the string collator |
|
85 | + * @return \Collator string collator |
|
86 | + */ |
|
87 | + private function getCollator() { |
|
88 | + if (!isset($this->collator)) { |
|
89 | + // looks like the default is en_US_POSIX which yields wrong sorting with |
|
90 | + // German umlauts, so using en_US instead |
|
91 | + if (class_exists('Collator')) { |
|
92 | + $this->collator = new \Collator('en_US'); |
|
93 | + } |
|
94 | + else { |
|
95 | + $this->collator = new \OC\NaturalSort_DefaultCollator(); |
|
96 | + } |
|
97 | + } |
|
98 | + return $this->collator; |
|
99 | + } |
|
100 | 100 | |
101 | - /** |
|
102 | - * Compare two strings to provide a natural sort |
|
103 | - * @param string $a first string to compare |
|
104 | - * @param string $b second string to compare |
|
105 | - * @return int -1 if $b comes before $a, 1 if $a comes before $b |
|
106 | - * or 0 if the strings are identical |
|
107 | - */ |
|
108 | - public function compare($a, $b) { |
|
109 | - // Needed because PHP doesn't sort correctly when numbers are enclosed in |
|
110 | - // parenthesis, even with NUMERIC_COLLATION enabled. |
|
111 | - // For example it gave ["test (2).txt", "test.txt"] |
|
112 | - // instead of ["test.txt", "test (2).txt"] |
|
113 | - $aa = self::naturalSortChunkify($a); |
|
114 | - $bb = self::naturalSortChunkify($b); |
|
101 | + /** |
|
102 | + * Compare two strings to provide a natural sort |
|
103 | + * @param string $a first string to compare |
|
104 | + * @param string $b second string to compare |
|
105 | + * @return int -1 if $b comes before $a, 1 if $a comes before $b |
|
106 | + * or 0 if the strings are identical |
|
107 | + */ |
|
108 | + public function compare($a, $b) { |
|
109 | + // Needed because PHP doesn't sort correctly when numbers are enclosed in |
|
110 | + // parenthesis, even with NUMERIC_COLLATION enabled. |
|
111 | + // For example it gave ["test (2).txt", "test.txt"] |
|
112 | + // instead of ["test.txt", "test (2).txt"] |
|
113 | + $aa = self::naturalSortChunkify($a); |
|
114 | + $bb = self::naturalSortChunkify($b); |
|
115 | 115 | |
116 | - for ($x = 0; isset($aa[$x]) && isset($bb[$x]); $x++) { |
|
117 | - $aChunk = $aa[$x]; |
|
118 | - $bChunk = $bb[$x]; |
|
119 | - if ($aChunk !== $bChunk) { |
|
120 | - // test first character (character comparison, not number comparison) |
|
121 | - if ($aChunk[0] >= '0' && $aChunk[0] <= '9' && $bChunk[0] >= '0' && $bChunk[0] <= '9') { |
|
122 | - $aNum = (int)$aChunk; |
|
123 | - $bNum = (int)$bChunk; |
|
124 | - return $aNum - $bNum; |
|
125 | - } |
|
126 | - return self::getCollator()->compare($aChunk, $bChunk); |
|
127 | - } |
|
128 | - } |
|
129 | - return count($aa) - count($bb); |
|
130 | - } |
|
116 | + for ($x = 0; isset($aa[$x]) && isset($bb[$x]); $x++) { |
|
117 | + $aChunk = $aa[$x]; |
|
118 | + $bChunk = $bb[$x]; |
|
119 | + if ($aChunk !== $bChunk) { |
|
120 | + // test first character (character comparison, not number comparison) |
|
121 | + if ($aChunk[0] >= '0' && $aChunk[0] <= '9' && $bChunk[0] >= '0' && $bChunk[0] <= '9') { |
|
122 | + $aNum = (int)$aChunk; |
|
123 | + $bNum = (int)$bChunk; |
|
124 | + return $aNum - $bNum; |
|
125 | + } |
|
126 | + return self::getCollator()->compare($aChunk, $bChunk); |
|
127 | + } |
|
128 | + } |
|
129 | + return count($aa) - count($bb); |
|
130 | + } |
|
131 | 131 | |
132 | - /** |
|
133 | - * Returns a singleton |
|
134 | - * @return \OC\NaturalSort instance |
|
135 | - */ |
|
136 | - public static function getInstance() { |
|
137 | - if (!isset(self::$instance)) { |
|
138 | - self::$instance = new \OC\NaturalSort(); |
|
139 | - } |
|
140 | - return self::$instance; |
|
141 | - } |
|
132 | + /** |
|
133 | + * Returns a singleton |
|
134 | + * @return \OC\NaturalSort instance |
|
135 | + */ |
|
136 | + public static function getInstance() { |
|
137 | + if (!isset(self::$instance)) { |
|
138 | + self::$instance = new \OC\NaturalSort(); |
|
139 | + } |
|
140 | + return self::$instance; |
|
141 | + } |
|
142 | 142 | } |
@@ -54,556 +54,556 @@ |
||
54 | 54 | */ |
55 | 55 | class Updater extends BasicEmitter { |
56 | 56 | |
57 | - /** @var ILogger $log */ |
|
58 | - private $log; |
|
59 | - |
|
60 | - /** @var IConfig */ |
|
61 | - private $config; |
|
62 | - |
|
63 | - /** @var Checker */ |
|
64 | - private $checker; |
|
65 | - |
|
66 | - /** @var Installer */ |
|
67 | - private $installer; |
|
68 | - |
|
69 | - private $logLevelNames = [ |
|
70 | - 0 => 'Debug', |
|
71 | - 1 => 'Info', |
|
72 | - 2 => 'Warning', |
|
73 | - 3 => 'Error', |
|
74 | - 4 => 'Fatal', |
|
75 | - ]; |
|
76 | - |
|
77 | - /** |
|
78 | - * @param IConfig $config |
|
79 | - * @param Checker $checker |
|
80 | - * @param ILogger $log |
|
81 | - * @param Installer $installer |
|
82 | - */ |
|
83 | - public function __construct(IConfig $config, |
|
84 | - Checker $checker, |
|
85 | - ILogger $log = null, |
|
86 | - Installer $installer) { |
|
87 | - $this->log = $log; |
|
88 | - $this->config = $config; |
|
89 | - $this->checker = $checker; |
|
90 | - $this->installer = $installer; |
|
91 | - } |
|
92 | - |
|
93 | - /** |
|
94 | - * runs the update actions in maintenance mode, does not upgrade the source files |
|
95 | - * except the main .htaccess file |
|
96 | - * |
|
97 | - * @return bool true if the operation succeeded, false otherwise |
|
98 | - */ |
|
99 | - public function upgrade() { |
|
100 | - $this->emitRepairEvents(); |
|
101 | - $this->logAllEvents(); |
|
102 | - |
|
103 | - $logLevel = $this->config->getSystemValue('loglevel', ILogger::WARN); |
|
104 | - $this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]); |
|
105 | - $this->config->setSystemValue('loglevel', ILogger::DEBUG); |
|
106 | - |
|
107 | - $wasMaintenanceModeEnabled = $this->config->getSystemValue('maintenance', false); |
|
108 | - |
|
109 | - if(!$wasMaintenanceModeEnabled) { |
|
110 | - $this->config->setSystemValue('maintenance', true); |
|
111 | - $this->emit('\OC\Updater', 'maintenanceEnabled'); |
|
112 | - } |
|
113 | - |
|
114 | - $installedVersion = $this->config->getSystemValue('version', '0.0.0'); |
|
115 | - $currentVersion = implode('.', \OCP\Util::getVersion()); |
|
116 | - $this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, array('app' => 'core')); |
|
117 | - |
|
118 | - $success = true; |
|
119 | - try { |
|
120 | - $this->doUpgrade($currentVersion, $installedVersion); |
|
121 | - } catch (HintException $exception) { |
|
122 | - $this->log->logException($exception, ['app' => 'core']); |
|
123 | - $this->emit('\OC\Updater', 'failure', array($exception->getMessage() . ': ' .$exception->getHint())); |
|
124 | - $success = false; |
|
125 | - } catch (\Exception $exception) { |
|
126 | - $this->log->logException($exception, ['app' => 'core']); |
|
127 | - $this->emit('\OC\Updater', 'failure', array(get_class($exception) . ': ' .$exception->getMessage())); |
|
128 | - $success = false; |
|
129 | - } |
|
130 | - |
|
131 | - $this->emit('\OC\Updater', 'updateEnd', array($success)); |
|
132 | - |
|
133 | - if(!$wasMaintenanceModeEnabled && $success) { |
|
134 | - $this->config->setSystemValue('maintenance', false); |
|
135 | - $this->emit('\OC\Updater', 'maintenanceDisabled'); |
|
136 | - } else { |
|
137 | - $this->emit('\OC\Updater', 'maintenanceActive'); |
|
138 | - } |
|
139 | - |
|
140 | - $this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]); |
|
141 | - $this->config->setSystemValue('loglevel', $logLevel); |
|
142 | - $this->config->setSystemValue('installed', true); |
|
143 | - |
|
144 | - return $success; |
|
145 | - } |
|
146 | - |
|
147 | - /** |
|
148 | - * Return version from which this version is allowed to upgrade from |
|
149 | - * |
|
150 | - * @return array allowed previous versions per vendor |
|
151 | - */ |
|
152 | - private function getAllowedPreviousVersions() { |
|
153 | - // this should really be a JSON file |
|
154 | - require \OC::$SERVERROOT . '/version.php'; |
|
155 | - /** @var array $OC_VersionCanBeUpgradedFrom */ |
|
156 | - return $OC_VersionCanBeUpgradedFrom; |
|
157 | - } |
|
158 | - |
|
159 | - /** |
|
160 | - * Return vendor from which this version was published |
|
161 | - * |
|
162 | - * @return string Get the vendor |
|
163 | - */ |
|
164 | - private function getVendor() { |
|
165 | - // this should really be a JSON file |
|
166 | - require \OC::$SERVERROOT . '/version.php'; |
|
167 | - /** @var string $vendor */ |
|
168 | - return (string) $vendor; |
|
169 | - } |
|
170 | - |
|
171 | - /** |
|
172 | - * Whether an upgrade to a specified version is possible |
|
173 | - * @param string $oldVersion |
|
174 | - * @param string $newVersion |
|
175 | - * @param array $allowedPreviousVersions |
|
176 | - * @return bool |
|
177 | - */ |
|
178 | - public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) { |
|
179 | - $version = explode('.', $oldVersion); |
|
180 | - $majorMinor = $version[0] . '.' . $version[1]; |
|
181 | - |
|
182 | - $currentVendor = $this->config->getAppValue('core', 'vendor', ''); |
|
183 | - |
|
184 | - // Vendor was not set correctly on install, so we have to white-list known versions |
|
185 | - if ($currentVendor === '' && isset($allowedPreviousVersions['owncloud'][$oldVersion])) { |
|
186 | - $currentVendor = 'owncloud'; |
|
187 | - } |
|
188 | - |
|
189 | - if ($currentVendor === 'nextcloud') { |
|
190 | - return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) |
|
191 | - && (version_compare($oldVersion, $newVersion, '<=') || |
|
192 | - $this->config->getSystemValue('debug', false)); |
|
193 | - } |
|
194 | - |
|
195 | - // Check if the instance can be migrated |
|
196 | - return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) || |
|
197 | - isset($allowedPreviousVersions[$currentVendor][$oldVersion]); |
|
198 | - } |
|
199 | - |
|
200 | - /** |
|
201 | - * runs the update actions in maintenance mode, does not upgrade the source files |
|
202 | - * except the main .htaccess file |
|
203 | - * |
|
204 | - * @param string $currentVersion current version to upgrade to |
|
205 | - * @param string $installedVersion previous version from which to upgrade from |
|
206 | - * |
|
207 | - * @throws \Exception |
|
208 | - */ |
|
209 | - private function doUpgrade($currentVersion, $installedVersion) { |
|
210 | - // Stop update if the update is over several major versions |
|
211 | - $allowedPreviousVersions = $this->getAllowedPreviousVersions(); |
|
212 | - if (!$this->isUpgradePossible($installedVersion, $currentVersion, $allowedPreviousVersions)) { |
|
213 | - throw new \Exception('Updates between multiple major versions and downgrades are unsupported.'); |
|
214 | - } |
|
215 | - |
|
216 | - // Update .htaccess files |
|
217 | - try { |
|
218 | - Setup::updateHtaccess(); |
|
219 | - Setup::protectDataDirectory(); |
|
220 | - } catch (\Exception $e) { |
|
221 | - throw new \Exception($e->getMessage()); |
|
222 | - } |
|
223 | - |
|
224 | - // create empty file in data dir, so we can later find |
|
225 | - // out that this is indeed an ownCloud data directory |
|
226 | - // (in case it didn't exist before) |
|
227 | - file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', ''); |
|
228 | - |
|
229 | - // pre-upgrade repairs |
|
230 | - $repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher()); |
|
231 | - $repair->run(); |
|
232 | - |
|
233 | - $this->doCoreUpgrade(); |
|
234 | - |
|
235 | - try { |
|
236 | - // TODO: replace with the new repair step mechanism https://github.com/owncloud/core/pull/24378 |
|
237 | - Setup::installBackgroundJobs(); |
|
238 | - } catch (\Exception $e) { |
|
239 | - throw new \Exception($e->getMessage()); |
|
240 | - } |
|
241 | - |
|
242 | - // update all shipped apps |
|
243 | - $this->checkAppsRequirements(); |
|
244 | - $this->doAppUpgrade(); |
|
245 | - |
|
246 | - // Update the appfetchers version so it downloads the correct list from the appstore |
|
247 | - \OC::$server->getAppFetcher()->setVersion($currentVersion); |
|
248 | - |
|
249 | - // upgrade appstore apps |
|
250 | - $this->upgradeAppStoreApps(\OC::$server->getAppManager()->getInstalledApps()); |
|
251 | - |
|
252 | - // install new shipped apps on upgrade |
|
253 | - OC_App::loadApps(['authentication']); |
|
254 | - $errors = Installer::installShippedApps(true); |
|
255 | - foreach ($errors as $appId => $exception) { |
|
256 | - /** @var \Exception $exception */ |
|
257 | - $this->log->logException($exception, ['app' => $appId]); |
|
258 | - $this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]); |
|
259 | - } |
|
260 | - |
|
261 | - // post-upgrade repairs |
|
262 | - $repair = new Repair(Repair::getRepairSteps(), \OC::$server->getEventDispatcher()); |
|
263 | - $repair->run(); |
|
264 | - |
|
265 | - //Invalidate update feed |
|
266 | - $this->config->setAppValue('core', 'lastupdatedat', 0); |
|
267 | - |
|
268 | - // Check for code integrity if not disabled |
|
269 | - if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) { |
|
270 | - $this->emit('\OC\Updater', 'startCheckCodeIntegrity'); |
|
271 | - $this->checker->runInstanceVerification(); |
|
272 | - $this->emit('\OC\Updater', 'finishedCheckCodeIntegrity'); |
|
273 | - } |
|
274 | - |
|
275 | - // only set the final version if everything went well |
|
276 | - $this->config->setSystemValue('version', implode('.', Util::getVersion())); |
|
277 | - $this->config->setAppValue('core', 'vendor', $this->getVendor()); |
|
278 | - } |
|
279 | - |
|
280 | - protected function doCoreUpgrade() { |
|
281 | - $this->emit('\OC\Updater', 'dbUpgradeBefore'); |
|
282 | - |
|
283 | - // execute core migrations |
|
284 | - $ms = new MigrationService('core', \OC::$server->getDatabaseConnection()); |
|
285 | - $ms->migrate(); |
|
286 | - |
|
287 | - $this->emit('\OC\Updater', 'dbUpgrade'); |
|
288 | - } |
|
289 | - |
|
290 | - /** |
|
291 | - * @param string $version the oc version to check app compatibility with |
|
292 | - */ |
|
293 | - protected function checkAppUpgrade($version) { |
|
294 | - $apps = \OC_App::getEnabledApps(); |
|
295 | - $this->emit('\OC\Updater', 'appUpgradeCheckBefore'); |
|
296 | - |
|
297 | - $appManager = \OC::$server->getAppManager(); |
|
298 | - foreach ($apps as $appId) { |
|
299 | - $info = \OC_App::getAppInfo($appId); |
|
300 | - $compatible = \OC_App::isAppCompatible($version, $info); |
|
301 | - $isShipped = $appManager->isShipped($appId); |
|
302 | - |
|
303 | - if ($compatible && $isShipped && \OC_App::shouldUpgrade($appId)) { |
|
304 | - /** |
|
305 | - * FIXME: The preupdate check is performed before the database migration, otherwise database changes |
|
306 | - * are not possible anymore within it. - Consider this when touching the code. |
|
307 | - * @link https://github.com/owncloud/core/issues/10980 |
|
308 | - * @see \OC_App::updateApp |
|
309 | - */ |
|
310 | - if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/preupdate.php')) { |
|
311 | - $this->includePreUpdate($appId); |
|
312 | - } |
|
313 | - if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) { |
|
314 | - $this->emit('\OC\Updater', 'appSimulateUpdate', array($appId)); |
|
315 | - \OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml'); |
|
316 | - } |
|
317 | - } |
|
318 | - } |
|
319 | - |
|
320 | - $this->emit('\OC\Updater', 'appUpgradeCheck'); |
|
321 | - } |
|
322 | - |
|
323 | - /** |
|
324 | - * Includes the pre-update file. Done here to prevent namespace mixups. |
|
325 | - * @param string $appId |
|
326 | - */ |
|
327 | - private function includePreUpdate($appId) { |
|
328 | - include \OC_App::getAppPath($appId) . '/appinfo/preupdate.php'; |
|
329 | - } |
|
330 | - |
|
331 | - /** |
|
332 | - * upgrades all apps within a major ownCloud upgrade. Also loads "priority" |
|
333 | - * (types authentication, filesystem, logging, in that order) afterwards. |
|
334 | - * |
|
335 | - * @throws NeedsUpdateException |
|
336 | - */ |
|
337 | - protected function doAppUpgrade() { |
|
338 | - $apps = \OC_App::getEnabledApps(); |
|
339 | - $priorityTypes = array('authentication', 'filesystem', 'logging'); |
|
340 | - $pseudoOtherType = 'other'; |
|
341 | - $stacks = array($pseudoOtherType => array()); |
|
342 | - |
|
343 | - foreach ($apps as $appId) { |
|
344 | - $priorityType = false; |
|
345 | - foreach ($priorityTypes as $type) { |
|
346 | - if(!isset($stacks[$type])) { |
|
347 | - $stacks[$type] = array(); |
|
348 | - } |
|
349 | - if (\OC_App::isType($appId, [$type])) { |
|
350 | - $stacks[$type][] = $appId; |
|
351 | - $priorityType = true; |
|
352 | - break; |
|
353 | - } |
|
354 | - } |
|
355 | - if (!$priorityType) { |
|
356 | - $stacks[$pseudoOtherType][] = $appId; |
|
357 | - } |
|
358 | - } |
|
359 | - foreach ($stacks as $type => $stack) { |
|
360 | - foreach ($stack as $appId) { |
|
361 | - if (\OC_App::shouldUpgrade($appId)) { |
|
362 | - $this->emit('\OC\Updater', 'appUpgradeStarted', [$appId, \OC_App::getAppVersion($appId)]); |
|
363 | - \OC_App::updateApp($appId); |
|
364 | - $this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]); |
|
365 | - } |
|
366 | - if($type !== $pseudoOtherType) { |
|
367 | - // load authentication, filesystem and logging apps after |
|
368 | - // upgrading them. Other apps my need to rely on modifying |
|
369 | - // user and/or filesystem aspects. |
|
370 | - \OC_App::loadApp($appId); |
|
371 | - } |
|
372 | - } |
|
373 | - } |
|
374 | - } |
|
375 | - |
|
376 | - /** |
|
377 | - * check if the current enabled apps are compatible with the current |
|
378 | - * ownCloud version. disable them if not. |
|
379 | - * This is important if you upgrade ownCloud and have non ported 3rd |
|
380 | - * party apps installed. |
|
381 | - * |
|
382 | - * @return array |
|
383 | - * @throws \Exception |
|
384 | - */ |
|
385 | - private function checkAppsRequirements() { |
|
386 | - $isCoreUpgrade = $this->isCodeUpgrade(); |
|
387 | - $apps = OC_App::getEnabledApps(); |
|
388 | - $version = implode('.', Util::getVersion()); |
|
389 | - $disabledApps = []; |
|
390 | - $appManager = \OC::$server->getAppManager(); |
|
391 | - foreach ($apps as $app) { |
|
392 | - // check if the app is compatible with this version of ownCloud |
|
393 | - $info = OC_App::getAppInfo($app); |
|
394 | - if($info === null || !OC_App::isAppCompatible($version, $info)) { |
|
395 | - if ($appManager->isShipped($app)) { |
|
396 | - throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update'); |
|
397 | - } |
|
398 | - \OC::$server->getAppManager()->disableApp($app); |
|
399 | - $this->emit('\OC\Updater', 'incompatibleAppDisabled', array($app)); |
|
400 | - } |
|
401 | - // no need to disable any app in case this is a non-core upgrade |
|
402 | - if (!$isCoreUpgrade) { |
|
403 | - continue; |
|
404 | - } |
|
405 | - // shipped apps will remain enabled |
|
406 | - if ($appManager->isShipped($app)) { |
|
407 | - continue; |
|
408 | - } |
|
409 | - // authentication and session apps will remain enabled as well |
|
410 | - if (OC_App::isType($app, ['session', 'authentication'])) { |
|
411 | - continue; |
|
412 | - } |
|
413 | - } |
|
414 | - return $disabledApps; |
|
415 | - } |
|
416 | - |
|
417 | - /** |
|
418 | - * @return bool |
|
419 | - */ |
|
420 | - private function isCodeUpgrade() { |
|
421 | - $installedVersion = $this->config->getSystemValue('version', '0.0.0'); |
|
422 | - $currentVersion = implode('.', Util::getVersion()); |
|
423 | - if (version_compare($currentVersion, $installedVersion, '>')) { |
|
424 | - return true; |
|
425 | - } |
|
426 | - return false; |
|
427 | - } |
|
428 | - |
|
429 | - /** |
|
430 | - * @param array $disabledApps |
|
431 | - * @throws \Exception |
|
432 | - */ |
|
433 | - private function upgradeAppStoreApps(array $disabledApps) { |
|
434 | - foreach($disabledApps as $app) { |
|
435 | - try { |
|
436 | - $this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]); |
|
437 | - if ($this->installer->isUpdateAvailable($app)) { |
|
438 | - $this->emit('\OC\Updater', 'upgradeAppStoreApp', [$app]); |
|
439 | - $this->installer->updateAppstoreApp($app); |
|
440 | - } |
|
441 | - $this->emit('\OC\Updater', 'checkAppStoreApp', [$app]); |
|
442 | - } catch (\Exception $ex) { |
|
443 | - $this->log->logException($ex, ['app' => 'core']); |
|
444 | - } |
|
445 | - } |
|
446 | - } |
|
447 | - |
|
448 | - /** |
|
449 | - * Forward messages emitted by the repair routine |
|
450 | - */ |
|
451 | - private function emitRepairEvents() { |
|
452 | - $dispatcher = \OC::$server->getEventDispatcher(); |
|
453 | - $dispatcher->addListener('\OC\Repair::warning', function ($event) { |
|
454 | - if ($event instanceof GenericEvent) { |
|
455 | - $this->emit('\OC\Updater', 'repairWarning', $event->getArguments()); |
|
456 | - } |
|
457 | - }); |
|
458 | - $dispatcher->addListener('\OC\Repair::error', function ($event) { |
|
459 | - if ($event instanceof GenericEvent) { |
|
460 | - $this->emit('\OC\Updater', 'repairError', $event->getArguments()); |
|
461 | - } |
|
462 | - }); |
|
463 | - $dispatcher->addListener('\OC\Repair::info', function ($event) { |
|
464 | - if ($event instanceof GenericEvent) { |
|
465 | - $this->emit('\OC\Updater', 'repairInfo', $event->getArguments()); |
|
466 | - } |
|
467 | - }); |
|
468 | - $dispatcher->addListener('\OC\Repair::step', function ($event) { |
|
469 | - if ($event instanceof GenericEvent) { |
|
470 | - $this->emit('\OC\Updater', 'repairStep', $event->getArguments()); |
|
471 | - } |
|
472 | - }); |
|
473 | - } |
|
474 | - |
|
475 | - private function logAllEvents() { |
|
476 | - $log = $this->log; |
|
477 | - |
|
478 | - $dispatcher = \OC::$server->getEventDispatcher(); |
|
479 | - $dispatcher->addListener('\OC\DB\Migrator::executeSql', function($event) use ($log) { |
|
480 | - if (!$event instanceof GenericEvent) { |
|
481 | - return; |
|
482 | - } |
|
483 | - $log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']); |
|
484 | - }); |
|
485 | - $dispatcher->addListener('\OC\DB\Migrator::checkTable', function($event) use ($log) { |
|
486 | - if (!$event instanceof GenericEvent) { |
|
487 | - return; |
|
488 | - } |
|
489 | - $log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']); |
|
490 | - }); |
|
491 | - |
|
492 | - $repairListener = function($event) use ($log) { |
|
493 | - if (!$event instanceof GenericEvent) { |
|
494 | - return; |
|
495 | - } |
|
496 | - switch ($event->getSubject()) { |
|
497 | - case '\OC\Repair::startProgress': |
|
498 | - $log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']); |
|
499 | - break; |
|
500 | - case '\OC\Repair::advance': |
|
501 | - $desc = $event->getArgument(1); |
|
502 | - if (empty($desc)) { |
|
503 | - $desc = ''; |
|
504 | - } |
|
505 | - $log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']); |
|
506 | - |
|
507 | - break; |
|
508 | - case '\OC\Repair::finishProgress': |
|
509 | - $log->info('\OC\Repair::finishProgress', ['app' => 'updater']); |
|
510 | - break; |
|
511 | - case '\OC\Repair::step': |
|
512 | - $log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']); |
|
513 | - break; |
|
514 | - case '\OC\Repair::info': |
|
515 | - $log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']); |
|
516 | - break; |
|
517 | - case '\OC\Repair::warning': |
|
518 | - $log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']); |
|
519 | - break; |
|
520 | - case '\OC\Repair::error': |
|
521 | - $log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']); |
|
522 | - break; |
|
523 | - } |
|
524 | - }; |
|
525 | - |
|
526 | - $dispatcher->addListener('\OC\Repair::startProgress', $repairListener); |
|
527 | - $dispatcher->addListener('\OC\Repair::advance', $repairListener); |
|
528 | - $dispatcher->addListener('\OC\Repair::finishProgress', $repairListener); |
|
529 | - $dispatcher->addListener('\OC\Repair::step', $repairListener); |
|
530 | - $dispatcher->addListener('\OC\Repair::info', $repairListener); |
|
531 | - $dispatcher->addListener('\OC\Repair::warning', $repairListener); |
|
532 | - $dispatcher->addListener('\OC\Repair::error', $repairListener); |
|
533 | - |
|
534 | - |
|
535 | - $this->listen('\OC\Updater', 'maintenanceEnabled', function () use($log) { |
|
536 | - $log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']); |
|
537 | - }); |
|
538 | - $this->listen('\OC\Updater', 'maintenanceDisabled', function () use($log) { |
|
539 | - $log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']); |
|
540 | - }); |
|
541 | - $this->listen('\OC\Updater', 'maintenanceActive', function () use($log) { |
|
542 | - $log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']); |
|
543 | - }); |
|
544 | - $this->listen('\OC\Updater', 'updateEnd', function ($success) use($log) { |
|
545 | - if ($success) { |
|
546 | - $log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']); |
|
547 | - } else { |
|
548 | - $log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']); |
|
549 | - } |
|
550 | - }); |
|
551 | - $this->listen('\OC\Updater', 'dbUpgradeBefore', function () use($log) { |
|
552 | - $log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']); |
|
553 | - }); |
|
554 | - $this->listen('\OC\Updater', 'dbUpgrade', function () use($log) { |
|
555 | - $log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']); |
|
556 | - }); |
|
557 | - $this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use($log) { |
|
558 | - $log->info('\OC\Updater::dbSimulateUpgradeBefore: Checking whether the database schema can be updated (this can take a long time depending on the database size)', ['app' => 'updater']); |
|
559 | - }); |
|
560 | - $this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use($log) { |
|
561 | - $log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']); |
|
562 | - }); |
|
563 | - $this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use($log) { |
|
564 | - $log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']); |
|
565 | - }); |
|
566 | - $this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use($log) { |
|
567 | - $log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']); |
|
568 | - }); |
|
569 | - $this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use($log) { |
|
570 | - $log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']); |
|
571 | - }); |
|
572 | - $this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use($log) { |
|
573 | - $log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']); |
|
574 | - }); |
|
575 | - $this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) { |
|
576 | - $log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']); |
|
577 | - }); |
|
578 | - $this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) { |
|
579 | - $log->info('\OC\Updater::appSimulateUpdate: Checking whether the database schema for <' . $app . '> can be updated (this can take a long time depending on the database size)', ['app' => 'updater']); |
|
580 | - }); |
|
581 | - $this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) { |
|
582 | - $log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']); |
|
583 | - }); |
|
584 | - $this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) { |
|
585 | - $log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']); |
|
586 | - }); |
|
587 | - $this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) { |
|
588 | - $log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']); |
|
589 | - }); |
|
590 | - $this->listen('\OC\Updater', 'failure', function ($message) use($log) { |
|
591 | - $log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']); |
|
592 | - }); |
|
593 | - $this->listen('\OC\Updater', 'setDebugLogLevel', function () use($log) { |
|
594 | - $log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']); |
|
595 | - }); |
|
596 | - $this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($log) { |
|
597 | - $log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']); |
|
598 | - }); |
|
599 | - $this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($log) { |
|
600 | - $log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']); |
|
601 | - }); |
|
602 | - $this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($log) { |
|
603 | - $log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']); |
|
604 | - }); |
|
605 | - |
|
606 | - } |
|
57 | + /** @var ILogger $log */ |
|
58 | + private $log; |
|
59 | + |
|
60 | + /** @var IConfig */ |
|
61 | + private $config; |
|
62 | + |
|
63 | + /** @var Checker */ |
|
64 | + private $checker; |
|
65 | + |
|
66 | + /** @var Installer */ |
|
67 | + private $installer; |
|
68 | + |
|
69 | + private $logLevelNames = [ |
|
70 | + 0 => 'Debug', |
|
71 | + 1 => 'Info', |
|
72 | + 2 => 'Warning', |
|
73 | + 3 => 'Error', |
|
74 | + 4 => 'Fatal', |
|
75 | + ]; |
|
76 | + |
|
77 | + /** |
|
78 | + * @param IConfig $config |
|
79 | + * @param Checker $checker |
|
80 | + * @param ILogger $log |
|
81 | + * @param Installer $installer |
|
82 | + */ |
|
83 | + public function __construct(IConfig $config, |
|
84 | + Checker $checker, |
|
85 | + ILogger $log = null, |
|
86 | + Installer $installer) { |
|
87 | + $this->log = $log; |
|
88 | + $this->config = $config; |
|
89 | + $this->checker = $checker; |
|
90 | + $this->installer = $installer; |
|
91 | + } |
|
92 | + |
|
93 | + /** |
|
94 | + * runs the update actions in maintenance mode, does not upgrade the source files |
|
95 | + * except the main .htaccess file |
|
96 | + * |
|
97 | + * @return bool true if the operation succeeded, false otherwise |
|
98 | + */ |
|
99 | + public function upgrade() { |
|
100 | + $this->emitRepairEvents(); |
|
101 | + $this->logAllEvents(); |
|
102 | + |
|
103 | + $logLevel = $this->config->getSystemValue('loglevel', ILogger::WARN); |
|
104 | + $this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]); |
|
105 | + $this->config->setSystemValue('loglevel', ILogger::DEBUG); |
|
106 | + |
|
107 | + $wasMaintenanceModeEnabled = $this->config->getSystemValue('maintenance', false); |
|
108 | + |
|
109 | + if(!$wasMaintenanceModeEnabled) { |
|
110 | + $this->config->setSystemValue('maintenance', true); |
|
111 | + $this->emit('\OC\Updater', 'maintenanceEnabled'); |
|
112 | + } |
|
113 | + |
|
114 | + $installedVersion = $this->config->getSystemValue('version', '0.0.0'); |
|
115 | + $currentVersion = implode('.', \OCP\Util::getVersion()); |
|
116 | + $this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, array('app' => 'core')); |
|
117 | + |
|
118 | + $success = true; |
|
119 | + try { |
|
120 | + $this->doUpgrade($currentVersion, $installedVersion); |
|
121 | + } catch (HintException $exception) { |
|
122 | + $this->log->logException($exception, ['app' => 'core']); |
|
123 | + $this->emit('\OC\Updater', 'failure', array($exception->getMessage() . ': ' .$exception->getHint())); |
|
124 | + $success = false; |
|
125 | + } catch (\Exception $exception) { |
|
126 | + $this->log->logException($exception, ['app' => 'core']); |
|
127 | + $this->emit('\OC\Updater', 'failure', array(get_class($exception) . ': ' .$exception->getMessage())); |
|
128 | + $success = false; |
|
129 | + } |
|
130 | + |
|
131 | + $this->emit('\OC\Updater', 'updateEnd', array($success)); |
|
132 | + |
|
133 | + if(!$wasMaintenanceModeEnabled && $success) { |
|
134 | + $this->config->setSystemValue('maintenance', false); |
|
135 | + $this->emit('\OC\Updater', 'maintenanceDisabled'); |
|
136 | + } else { |
|
137 | + $this->emit('\OC\Updater', 'maintenanceActive'); |
|
138 | + } |
|
139 | + |
|
140 | + $this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]); |
|
141 | + $this->config->setSystemValue('loglevel', $logLevel); |
|
142 | + $this->config->setSystemValue('installed', true); |
|
143 | + |
|
144 | + return $success; |
|
145 | + } |
|
146 | + |
|
147 | + /** |
|
148 | + * Return version from which this version is allowed to upgrade from |
|
149 | + * |
|
150 | + * @return array allowed previous versions per vendor |
|
151 | + */ |
|
152 | + private function getAllowedPreviousVersions() { |
|
153 | + // this should really be a JSON file |
|
154 | + require \OC::$SERVERROOT . '/version.php'; |
|
155 | + /** @var array $OC_VersionCanBeUpgradedFrom */ |
|
156 | + return $OC_VersionCanBeUpgradedFrom; |
|
157 | + } |
|
158 | + |
|
159 | + /** |
|
160 | + * Return vendor from which this version was published |
|
161 | + * |
|
162 | + * @return string Get the vendor |
|
163 | + */ |
|
164 | + private function getVendor() { |
|
165 | + // this should really be a JSON file |
|
166 | + require \OC::$SERVERROOT . '/version.php'; |
|
167 | + /** @var string $vendor */ |
|
168 | + return (string) $vendor; |
|
169 | + } |
|
170 | + |
|
171 | + /** |
|
172 | + * Whether an upgrade to a specified version is possible |
|
173 | + * @param string $oldVersion |
|
174 | + * @param string $newVersion |
|
175 | + * @param array $allowedPreviousVersions |
|
176 | + * @return bool |
|
177 | + */ |
|
178 | + public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) { |
|
179 | + $version = explode('.', $oldVersion); |
|
180 | + $majorMinor = $version[0] . '.' . $version[1]; |
|
181 | + |
|
182 | + $currentVendor = $this->config->getAppValue('core', 'vendor', ''); |
|
183 | + |
|
184 | + // Vendor was not set correctly on install, so we have to white-list known versions |
|
185 | + if ($currentVendor === '' && isset($allowedPreviousVersions['owncloud'][$oldVersion])) { |
|
186 | + $currentVendor = 'owncloud'; |
|
187 | + } |
|
188 | + |
|
189 | + if ($currentVendor === 'nextcloud') { |
|
190 | + return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) |
|
191 | + && (version_compare($oldVersion, $newVersion, '<=') || |
|
192 | + $this->config->getSystemValue('debug', false)); |
|
193 | + } |
|
194 | + |
|
195 | + // Check if the instance can be migrated |
|
196 | + return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) || |
|
197 | + isset($allowedPreviousVersions[$currentVendor][$oldVersion]); |
|
198 | + } |
|
199 | + |
|
200 | + /** |
|
201 | + * runs the update actions in maintenance mode, does not upgrade the source files |
|
202 | + * except the main .htaccess file |
|
203 | + * |
|
204 | + * @param string $currentVersion current version to upgrade to |
|
205 | + * @param string $installedVersion previous version from which to upgrade from |
|
206 | + * |
|
207 | + * @throws \Exception |
|
208 | + */ |
|
209 | + private function doUpgrade($currentVersion, $installedVersion) { |
|
210 | + // Stop update if the update is over several major versions |
|
211 | + $allowedPreviousVersions = $this->getAllowedPreviousVersions(); |
|
212 | + if (!$this->isUpgradePossible($installedVersion, $currentVersion, $allowedPreviousVersions)) { |
|
213 | + throw new \Exception('Updates between multiple major versions and downgrades are unsupported.'); |
|
214 | + } |
|
215 | + |
|
216 | + // Update .htaccess files |
|
217 | + try { |
|
218 | + Setup::updateHtaccess(); |
|
219 | + Setup::protectDataDirectory(); |
|
220 | + } catch (\Exception $e) { |
|
221 | + throw new \Exception($e->getMessage()); |
|
222 | + } |
|
223 | + |
|
224 | + // create empty file in data dir, so we can later find |
|
225 | + // out that this is indeed an ownCloud data directory |
|
226 | + // (in case it didn't exist before) |
|
227 | + file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', ''); |
|
228 | + |
|
229 | + // pre-upgrade repairs |
|
230 | + $repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher()); |
|
231 | + $repair->run(); |
|
232 | + |
|
233 | + $this->doCoreUpgrade(); |
|
234 | + |
|
235 | + try { |
|
236 | + // TODO: replace with the new repair step mechanism https://github.com/owncloud/core/pull/24378 |
|
237 | + Setup::installBackgroundJobs(); |
|
238 | + } catch (\Exception $e) { |
|
239 | + throw new \Exception($e->getMessage()); |
|
240 | + } |
|
241 | + |
|
242 | + // update all shipped apps |
|
243 | + $this->checkAppsRequirements(); |
|
244 | + $this->doAppUpgrade(); |
|
245 | + |
|
246 | + // Update the appfetchers version so it downloads the correct list from the appstore |
|
247 | + \OC::$server->getAppFetcher()->setVersion($currentVersion); |
|
248 | + |
|
249 | + // upgrade appstore apps |
|
250 | + $this->upgradeAppStoreApps(\OC::$server->getAppManager()->getInstalledApps()); |
|
251 | + |
|
252 | + // install new shipped apps on upgrade |
|
253 | + OC_App::loadApps(['authentication']); |
|
254 | + $errors = Installer::installShippedApps(true); |
|
255 | + foreach ($errors as $appId => $exception) { |
|
256 | + /** @var \Exception $exception */ |
|
257 | + $this->log->logException($exception, ['app' => $appId]); |
|
258 | + $this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]); |
|
259 | + } |
|
260 | + |
|
261 | + // post-upgrade repairs |
|
262 | + $repair = new Repair(Repair::getRepairSteps(), \OC::$server->getEventDispatcher()); |
|
263 | + $repair->run(); |
|
264 | + |
|
265 | + //Invalidate update feed |
|
266 | + $this->config->setAppValue('core', 'lastupdatedat', 0); |
|
267 | + |
|
268 | + // Check for code integrity if not disabled |
|
269 | + if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) { |
|
270 | + $this->emit('\OC\Updater', 'startCheckCodeIntegrity'); |
|
271 | + $this->checker->runInstanceVerification(); |
|
272 | + $this->emit('\OC\Updater', 'finishedCheckCodeIntegrity'); |
|
273 | + } |
|
274 | + |
|
275 | + // only set the final version if everything went well |
|
276 | + $this->config->setSystemValue('version', implode('.', Util::getVersion())); |
|
277 | + $this->config->setAppValue('core', 'vendor', $this->getVendor()); |
|
278 | + } |
|
279 | + |
|
280 | + protected function doCoreUpgrade() { |
|
281 | + $this->emit('\OC\Updater', 'dbUpgradeBefore'); |
|
282 | + |
|
283 | + // execute core migrations |
|
284 | + $ms = new MigrationService('core', \OC::$server->getDatabaseConnection()); |
|
285 | + $ms->migrate(); |
|
286 | + |
|
287 | + $this->emit('\OC\Updater', 'dbUpgrade'); |
|
288 | + } |
|
289 | + |
|
290 | + /** |
|
291 | + * @param string $version the oc version to check app compatibility with |
|
292 | + */ |
|
293 | + protected function checkAppUpgrade($version) { |
|
294 | + $apps = \OC_App::getEnabledApps(); |
|
295 | + $this->emit('\OC\Updater', 'appUpgradeCheckBefore'); |
|
296 | + |
|
297 | + $appManager = \OC::$server->getAppManager(); |
|
298 | + foreach ($apps as $appId) { |
|
299 | + $info = \OC_App::getAppInfo($appId); |
|
300 | + $compatible = \OC_App::isAppCompatible($version, $info); |
|
301 | + $isShipped = $appManager->isShipped($appId); |
|
302 | + |
|
303 | + if ($compatible && $isShipped && \OC_App::shouldUpgrade($appId)) { |
|
304 | + /** |
|
305 | + * FIXME: The preupdate check is performed before the database migration, otherwise database changes |
|
306 | + * are not possible anymore within it. - Consider this when touching the code. |
|
307 | + * @link https://github.com/owncloud/core/issues/10980 |
|
308 | + * @see \OC_App::updateApp |
|
309 | + */ |
|
310 | + if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/preupdate.php')) { |
|
311 | + $this->includePreUpdate($appId); |
|
312 | + } |
|
313 | + if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) { |
|
314 | + $this->emit('\OC\Updater', 'appSimulateUpdate', array($appId)); |
|
315 | + \OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml'); |
|
316 | + } |
|
317 | + } |
|
318 | + } |
|
319 | + |
|
320 | + $this->emit('\OC\Updater', 'appUpgradeCheck'); |
|
321 | + } |
|
322 | + |
|
323 | + /** |
|
324 | + * Includes the pre-update file. Done here to prevent namespace mixups. |
|
325 | + * @param string $appId |
|
326 | + */ |
|
327 | + private function includePreUpdate($appId) { |
|
328 | + include \OC_App::getAppPath($appId) . '/appinfo/preupdate.php'; |
|
329 | + } |
|
330 | + |
|
331 | + /** |
|
332 | + * upgrades all apps within a major ownCloud upgrade. Also loads "priority" |
|
333 | + * (types authentication, filesystem, logging, in that order) afterwards. |
|
334 | + * |
|
335 | + * @throws NeedsUpdateException |
|
336 | + */ |
|
337 | + protected function doAppUpgrade() { |
|
338 | + $apps = \OC_App::getEnabledApps(); |
|
339 | + $priorityTypes = array('authentication', 'filesystem', 'logging'); |
|
340 | + $pseudoOtherType = 'other'; |
|
341 | + $stacks = array($pseudoOtherType => array()); |
|
342 | + |
|
343 | + foreach ($apps as $appId) { |
|
344 | + $priorityType = false; |
|
345 | + foreach ($priorityTypes as $type) { |
|
346 | + if(!isset($stacks[$type])) { |
|
347 | + $stacks[$type] = array(); |
|
348 | + } |
|
349 | + if (\OC_App::isType($appId, [$type])) { |
|
350 | + $stacks[$type][] = $appId; |
|
351 | + $priorityType = true; |
|
352 | + break; |
|
353 | + } |
|
354 | + } |
|
355 | + if (!$priorityType) { |
|
356 | + $stacks[$pseudoOtherType][] = $appId; |
|
357 | + } |
|
358 | + } |
|
359 | + foreach ($stacks as $type => $stack) { |
|
360 | + foreach ($stack as $appId) { |
|
361 | + if (\OC_App::shouldUpgrade($appId)) { |
|
362 | + $this->emit('\OC\Updater', 'appUpgradeStarted', [$appId, \OC_App::getAppVersion($appId)]); |
|
363 | + \OC_App::updateApp($appId); |
|
364 | + $this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]); |
|
365 | + } |
|
366 | + if($type !== $pseudoOtherType) { |
|
367 | + // load authentication, filesystem and logging apps after |
|
368 | + // upgrading them. Other apps my need to rely on modifying |
|
369 | + // user and/or filesystem aspects. |
|
370 | + \OC_App::loadApp($appId); |
|
371 | + } |
|
372 | + } |
|
373 | + } |
|
374 | + } |
|
375 | + |
|
376 | + /** |
|
377 | + * check if the current enabled apps are compatible with the current |
|
378 | + * ownCloud version. disable them if not. |
|
379 | + * This is important if you upgrade ownCloud and have non ported 3rd |
|
380 | + * party apps installed. |
|
381 | + * |
|
382 | + * @return array |
|
383 | + * @throws \Exception |
|
384 | + */ |
|
385 | + private function checkAppsRequirements() { |
|
386 | + $isCoreUpgrade = $this->isCodeUpgrade(); |
|
387 | + $apps = OC_App::getEnabledApps(); |
|
388 | + $version = implode('.', Util::getVersion()); |
|
389 | + $disabledApps = []; |
|
390 | + $appManager = \OC::$server->getAppManager(); |
|
391 | + foreach ($apps as $app) { |
|
392 | + // check if the app is compatible with this version of ownCloud |
|
393 | + $info = OC_App::getAppInfo($app); |
|
394 | + if($info === null || !OC_App::isAppCompatible($version, $info)) { |
|
395 | + if ($appManager->isShipped($app)) { |
|
396 | + throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update'); |
|
397 | + } |
|
398 | + \OC::$server->getAppManager()->disableApp($app); |
|
399 | + $this->emit('\OC\Updater', 'incompatibleAppDisabled', array($app)); |
|
400 | + } |
|
401 | + // no need to disable any app in case this is a non-core upgrade |
|
402 | + if (!$isCoreUpgrade) { |
|
403 | + continue; |
|
404 | + } |
|
405 | + // shipped apps will remain enabled |
|
406 | + if ($appManager->isShipped($app)) { |
|
407 | + continue; |
|
408 | + } |
|
409 | + // authentication and session apps will remain enabled as well |
|
410 | + if (OC_App::isType($app, ['session', 'authentication'])) { |
|
411 | + continue; |
|
412 | + } |
|
413 | + } |
|
414 | + return $disabledApps; |
|
415 | + } |
|
416 | + |
|
417 | + /** |
|
418 | + * @return bool |
|
419 | + */ |
|
420 | + private function isCodeUpgrade() { |
|
421 | + $installedVersion = $this->config->getSystemValue('version', '0.0.0'); |
|
422 | + $currentVersion = implode('.', Util::getVersion()); |
|
423 | + if (version_compare($currentVersion, $installedVersion, '>')) { |
|
424 | + return true; |
|
425 | + } |
|
426 | + return false; |
|
427 | + } |
|
428 | + |
|
429 | + /** |
|
430 | + * @param array $disabledApps |
|
431 | + * @throws \Exception |
|
432 | + */ |
|
433 | + private function upgradeAppStoreApps(array $disabledApps) { |
|
434 | + foreach($disabledApps as $app) { |
|
435 | + try { |
|
436 | + $this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]); |
|
437 | + if ($this->installer->isUpdateAvailable($app)) { |
|
438 | + $this->emit('\OC\Updater', 'upgradeAppStoreApp', [$app]); |
|
439 | + $this->installer->updateAppstoreApp($app); |
|
440 | + } |
|
441 | + $this->emit('\OC\Updater', 'checkAppStoreApp', [$app]); |
|
442 | + } catch (\Exception $ex) { |
|
443 | + $this->log->logException($ex, ['app' => 'core']); |
|
444 | + } |
|
445 | + } |
|
446 | + } |
|
447 | + |
|
448 | + /** |
|
449 | + * Forward messages emitted by the repair routine |
|
450 | + */ |
|
451 | + private function emitRepairEvents() { |
|
452 | + $dispatcher = \OC::$server->getEventDispatcher(); |
|
453 | + $dispatcher->addListener('\OC\Repair::warning', function ($event) { |
|
454 | + if ($event instanceof GenericEvent) { |
|
455 | + $this->emit('\OC\Updater', 'repairWarning', $event->getArguments()); |
|
456 | + } |
|
457 | + }); |
|
458 | + $dispatcher->addListener('\OC\Repair::error', function ($event) { |
|
459 | + if ($event instanceof GenericEvent) { |
|
460 | + $this->emit('\OC\Updater', 'repairError', $event->getArguments()); |
|
461 | + } |
|
462 | + }); |
|
463 | + $dispatcher->addListener('\OC\Repair::info', function ($event) { |
|
464 | + if ($event instanceof GenericEvent) { |
|
465 | + $this->emit('\OC\Updater', 'repairInfo', $event->getArguments()); |
|
466 | + } |
|
467 | + }); |
|
468 | + $dispatcher->addListener('\OC\Repair::step', function ($event) { |
|
469 | + if ($event instanceof GenericEvent) { |
|
470 | + $this->emit('\OC\Updater', 'repairStep', $event->getArguments()); |
|
471 | + } |
|
472 | + }); |
|
473 | + } |
|
474 | + |
|
475 | + private function logAllEvents() { |
|
476 | + $log = $this->log; |
|
477 | + |
|
478 | + $dispatcher = \OC::$server->getEventDispatcher(); |
|
479 | + $dispatcher->addListener('\OC\DB\Migrator::executeSql', function($event) use ($log) { |
|
480 | + if (!$event instanceof GenericEvent) { |
|
481 | + return; |
|
482 | + } |
|
483 | + $log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']); |
|
484 | + }); |
|
485 | + $dispatcher->addListener('\OC\DB\Migrator::checkTable', function($event) use ($log) { |
|
486 | + if (!$event instanceof GenericEvent) { |
|
487 | + return; |
|
488 | + } |
|
489 | + $log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']); |
|
490 | + }); |
|
491 | + |
|
492 | + $repairListener = function($event) use ($log) { |
|
493 | + if (!$event instanceof GenericEvent) { |
|
494 | + return; |
|
495 | + } |
|
496 | + switch ($event->getSubject()) { |
|
497 | + case '\OC\Repair::startProgress': |
|
498 | + $log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']); |
|
499 | + break; |
|
500 | + case '\OC\Repair::advance': |
|
501 | + $desc = $event->getArgument(1); |
|
502 | + if (empty($desc)) { |
|
503 | + $desc = ''; |
|
504 | + } |
|
505 | + $log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']); |
|
506 | + |
|
507 | + break; |
|
508 | + case '\OC\Repair::finishProgress': |
|
509 | + $log->info('\OC\Repair::finishProgress', ['app' => 'updater']); |
|
510 | + break; |
|
511 | + case '\OC\Repair::step': |
|
512 | + $log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']); |
|
513 | + break; |
|
514 | + case '\OC\Repair::info': |
|
515 | + $log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']); |
|
516 | + break; |
|
517 | + case '\OC\Repair::warning': |
|
518 | + $log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']); |
|
519 | + break; |
|
520 | + case '\OC\Repair::error': |
|
521 | + $log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']); |
|
522 | + break; |
|
523 | + } |
|
524 | + }; |
|
525 | + |
|
526 | + $dispatcher->addListener('\OC\Repair::startProgress', $repairListener); |
|
527 | + $dispatcher->addListener('\OC\Repair::advance', $repairListener); |
|
528 | + $dispatcher->addListener('\OC\Repair::finishProgress', $repairListener); |
|
529 | + $dispatcher->addListener('\OC\Repair::step', $repairListener); |
|
530 | + $dispatcher->addListener('\OC\Repair::info', $repairListener); |
|
531 | + $dispatcher->addListener('\OC\Repair::warning', $repairListener); |
|
532 | + $dispatcher->addListener('\OC\Repair::error', $repairListener); |
|
533 | + |
|
534 | + |
|
535 | + $this->listen('\OC\Updater', 'maintenanceEnabled', function () use($log) { |
|
536 | + $log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']); |
|
537 | + }); |
|
538 | + $this->listen('\OC\Updater', 'maintenanceDisabled', function () use($log) { |
|
539 | + $log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']); |
|
540 | + }); |
|
541 | + $this->listen('\OC\Updater', 'maintenanceActive', function () use($log) { |
|
542 | + $log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']); |
|
543 | + }); |
|
544 | + $this->listen('\OC\Updater', 'updateEnd', function ($success) use($log) { |
|
545 | + if ($success) { |
|
546 | + $log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']); |
|
547 | + } else { |
|
548 | + $log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']); |
|
549 | + } |
|
550 | + }); |
|
551 | + $this->listen('\OC\Updater', 'dbUpgradeBefore', function () use($log) { |
|
552 | + $log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']); |
|
553 | + }); |
|
554 | + $this->listen('\OC\Updater', 'dbUpgrade', function () use($log) { |
|
555 | + $log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']); |
|
556 | + }); |
|
557 | + $this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use($log) { |
|
558 | + $log->info('\OC\Updater::dbSimulateUpgradeBefore: Checking whether the database schema can be updated (this can take a long time depending on the database size)', ['app' => 'updater']); |
|
559 | + }); |
|
560 | + $this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use($log) { |
|
561 | + $log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']); |
|
562 | + }); |
|
563 | + $this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use($log) { |
|
564 | + $log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']); |
|
565 | + }); |
|
566 | + $this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use($log) { |
|
567 | + $log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']); |
|
568 | + }); |
|
569 | + $this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use($log) { |
|
570 | + $log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']); |
|
571 | + }); |
|
572 | + $this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use($log) { |
|
573 | + $log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']); |
|
574 | + }); |
|
575 | + $this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) { |
|
576 | + $log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']); |
|
577 | + }); |
|
578 | + $this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) { |
|
579 | + $log->info('\OC\Updater::appSimulateUpdate: Checking whether the database schema for <' . $app . '> can be updated (this can take a long time depending on the database size)', ['app' => 'updater']); |
|
580 | + }); |
|
581 | + $this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) { |
|
582 | + $log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']); |
|
583 | + }); |
|
584 | + $this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) { |
|
585 | + $log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']); |
|
586 | + }); |
|
587 | + $this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) { |
|
588 | + $log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']); |
|
589 | + }); |
|
590 | + $this->listen('\OC\Updater', 'failure', function ($message) use($log) { |
|
591 | + $log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']); |
|
592 | + }); |
|
593 | + $this->listen('\OC\Updater', 'setDebugLogLevel', function () use($log) { |
|
594 | + $log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']); |
|
595 | + }); |
|
596 | + $this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($log) { |
|
597 | + $log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']); |
|
598 | + }); |
|
599 | + $this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($log) { |
|
600 | + $log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']); |
|
601 | + }); |
|
602 | + $this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($log) { |
|
603 | + $log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']); |
|
604 | + }); |
|
605 | + |
|
606 | + } |
|
607 | 607 | |
608 | 608 | } |
609 | 609 |
@@ -101,43 +101,43 @@ discard block |
||
101 | 101 | $this->logAllEvents(); |
102 | 102 | |
103 | 103 | $logLevel = $this->config->getSystemValue('loglevel', ILogger::WARN); |
104 | - $this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]); |
|
104 | + $this->emit('\OC\Updater', 'setDebugLogLevel', [$logLevel, $this->logLevelNames[$logLevel]]); |
|
105 | 105 | $this->config->setSystemValue('loglevel', ILogger::DEBUG); |
106 | 106 | |
107 | 107 | $wasMaintenanceModeEnabled = $this->config->getSystemValue('maintenance', false); |
108 | 108 | |
109 | - if(!$wasMaintenanceModeEnabled) { |
|
109 | + if (!$wasMaintenanceModeEnabled) { |
|
110 | 110 | $this->config->setSystemValue('maintenance', true); |
111 | 111 | $this->emit('\OC\Updater', 'maintenanceEnabled'); |
112 | 112 | } |
113 | 113 | |
114 | 114 | $installedVersion = $this->config->getSystemValue('version', '0.0.0'); |
115 | 115 | $currentVersion = implode('.', \OCP\Util::getVersion()); |
116 | - $this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, array('app' => 'core')); |
|
116 | + $this->log->debug('starting upgrade from '.$installedVersion.' to '.$currentVersion, array('app' => 'core')); |
|
117 | 117 | |
118 | 118 | $success = true; |
119 | 119 | try { |
120 | 120 | $this->doUpgrade($currentVersion, $installedVersion); |
121 | 121 | } catch (HintException $exception) { |
122 | 122 | $this->log->logException($exception, ['app' => 'core']); |
123 | - $this->emit('\OC\Updater', 'failure', array($exception->getMessage() . ': ' .$exception->getHint())); |
|
123 | + $this->emit('\OC\Updater', 'failure', array($exception->getMessage().': '.$exception->getHint())); |
|
124 | 124 | $success = false; |
125 | 125 | } catch (\Exception $exception) { |
126 | 126 | $this->log->logException($exception, ['app' => 'core']); |
127 | - $this->emit('\OC\Updater', 'failure', array(get_class($exception) . ': ' .$exception->getMessage())); |
|
127 | + $this->emit('\OC\Updater', 'failure', array(get_class($exception).': '.$exception->getMessage())); |
|
128 | 128 | $success = false; |
129 | 129 | } |
130 | 130 | |
131 | 131 | $this->emit('\OC\Updater', 'updateEnd', array($success)); |
132 | 132 | |
133 | - if(!$wasMaintenanceModeEnabled && $success) { |
|
133 | + if (!$wasMaintenanceModeEnabled && $success) { |
|
134 | 134 | $this->config->setSystemValue('maintenance', false); |
135 | 135 | $this->emit('\OC\Updater', 'maintenanceDisabled'); |
136 | 136 | } else { |
137 | 137 | $this->emit('\OC\Updater', 'maintenanceActive'); |
138 | 138 | } |
139 | 139 | |
140 | - $this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]); |
|
140 | + $this->emit('\OC\Updater', 'resetLogLevel', [$logLevel, $this->logLevelNames[$logLevel]]); |
|
141 | 141 | $this->config->setSystemValue('loglevel', $logLevel); |
142 | 142 | $this->config->setSystemValue('installed', true); |
143 | 143 | |
@@ -151,7 +151,7 @@ discard block |
||
151 | 151 | */ |
152 | 152 | private function getAllowedPreviousVersions() { |
153 | 153 | // this should really be a JSON file |
154 | - require \OC::$SERVERROOT . '/version.php'; |
|
154 | + require \OC::$SERVERROOT.'/version.php'; |
|
155 | 155 | /** @var array $OC_VersionCanBeUpgradedFrom */ |
156 | 156 | return $OC_VersionCanBeUpgradedFrom; |
157 | 157 | } |
@@ -163,7 +163,7 @@ discard block |
||
163 | 163 | */ |
164 | 164 | private function getVendor() { |
165 | 165 | // this should really be a JSON file |
166 | - require \OC::$SERVERROOT . '/version.php'; |
|
166 | + require \OC::$SERVERROOT.'/version.php'; |
|
167 | 167 | /** @var string $vendor */ |
168 | 168 | return (string) $vendor; |
169 | 169 | } |
@@ -177,7 +177,7 @@ discard block |
||
177 | 177 | */ |
178 | 178 | public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) { |
179 | 179 | $version = explode('.', $oldVersion); |
180 | - $majorMinor = $version[0] . '.' . $version[1]; |
|
180 | + $majorMinor = $version[0].'.'.$version[1]; |
|
181 | 181 | |
182 | 182 | $currentVendor = $this->config->getAppValue('core', 'vendor', ''); |
183 | 183 | |
@@ -224,7 +224,7 @@ discard block |
||
224 | 224 | // create empty file in data dir, so we can later find |
225 | 225 | // out that this is indeed an ownCloud data directory |
226 | 226 | // (in case it didn't exist before) |
227 | - file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', ''); |
|
227 | + file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT.'/data').'/.ocdata', ''); |
|
228 | 228 | |
229 | 229 | // pre-upgrade repairs |
230 | 230 | $repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher()); |
@@ -255,7 +255,7 @@ discard block |
||
255 | 255 | foreach ($errors as $appId => $exception) { |
256 | 256 | /** @var \Exception $exception */ |
257 | 257 | $this->log->logException($exception, ['app' => $appId]); |
258 | - $this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]); |
|
258 | + $this->emit('\OC\Updater', 'failure', [$appId.': '.$exception->getMessage()]); |
|
259 | 259 | } |
260 | 260 | |
261 | 261 | // post-upgrade repairs |
@@ -266,7 +266,7 @@ discard block |
||
266 | 266 | $this->config->setAppValue('core', 'lastupdatedat', 0); |
267 | 267 | |
268 | 268 | // Check for code integrity if not disabled |
269 | - if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) { |
|
269 | + if (\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) { |
|
270 | 270 | $this->emit('\OC\Updater', 'startCheckCodeIntegrity'); |
271 | 271 | $this->checker->runInstanceVerification(); |
272 | 272 | $this->emit('\OC\Updater', 'finishedCheckCodeIntegrity'); |
@@ -307,12 +307,12 @@ discard block |
||
307 | 307 | * @link https://github.com/owncloud/core/issues/10980 |
308 | 308 | * @see \OC_App::updateApp |
309 | 309 | */ |
310 | - if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/preupdate.php')) { |
|
310 | + if (file_exists(\OC_App::getAppPath($appId).'/appinfo/preupdate.php')) { |
|
311 | 311 | $this->includePreUpdate($appId); |
312 | 312 | } |
313 | - if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) { |
|
313 | + if (file_exists(\OC_App::getAppPath($appId).'/appinfo/database.xml')) { |
|
314 | 314 | $this->emit('\OC\Updater', 'appSimulateUpdate', array($appId)); |
315 | - \OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml'); |
|
315 | + \OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId).'/appinfo/database.xml'); |
|
316 | 316 | } |
317 | 317 | } |
318 | 318 | } |
@@ -325,7 +325,7 @@ discard block |
||
325 | 325 | * @param string $appId |
326 | 326 | */ |
327 | 327 | private function includePreUpdate($appId) { |
328 | - include \OC_App::getAppPath($appId) . '/appinfo/preupdate.php'; |
|
328 | + include \OC_App::getAppPath($appId).'/appinfo/preupdate.php'; |
|
329 | 329 | } |
330 | 330 | |
331 | 331 | /** |
@@ -343,7 +343,7 @@ discard block |
||
343 | 343 | foreach ($apps as $appId) { |
344 | 344 | $priorityType = false; |
345 | 345 | foreach ($priorityTypes as $type) { |
346 | - if(!isset($stacks[$type])) { |
|
346 | + if (!isset($stacks[$type])) { |
|
347 | 347 | $stacks[$type] = array(); |
348 | 348 | } |
349 | 349 | if (\OC_App::isType($appId, [$type])) { |
@@ -363,7 +363,7 @@ discard block |
||
363 | 363 | \OC_App::updateApp($appId); |
364 | 364 | $this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]); |
365 | 365 | } |
366 | - if($type !== $pseudoOtherType) { |
|
366 | + if ($type !== $pseudoOtherType) { |
|
367 | 367 | // load authentication, filesystem and logging apps after |
368 | 368 | // upgrading them. Other apps my need to rely on modifying |
369 | 369 | // user and/or filesystem aspects. |
@@ -391,9 +391,9 @@ discard block |
||
391 | 391 | foreach ($apps as $app) { |
392 | 392 | // check if the app is compatible with this version of ownCloud |
393 | 393 | $info = OC_App::getAppInfo($app); |
394 | - if($info === null || !OC_App::isAppCompatible($version, $info)) { |
|
394 | + if ($info === null || !OC_App::isAppCompatible($version, $info)) { |
|
395 | 395 | if ($appManager->isShipped($app)) { |
396 | - throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update'); |
|
396 | + throw new \UnexpectedValueException('The files of the app "'.$app.'" were not correctly replaced before running the update'); |
|
397 | 397 | } |
398 | 398 | \OC::$server->getAppManager()->disableApp($app); |
399 | 399 | $this->emit('\OC\Updater', 'incompatibleAppDisabled', array($app)); |
@@ -431,7 +431,7 @@ discard block |
||
431 | 431 | * @throws \Exception |
432 | 432 | */ |
433 | 433 | private function upgradeAppStoreApps(array $disabledApps) { |
434 | - foreach($disabledApps as $app) { |
|
434 | + foreach ($disabledApps as $app) { |
|
435 | 435 | try { |
436 | 436 | $this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]); |
437 | 437 | if ($this->installer->isUpdateAvailable($app)) { |
@@ -450,22 +450,22 @@ discard block |
||
450 | 450 | */ |
451 | 451 | private function emitRepairEvents() { |
452 | 452 | $dispatcher = \OC::$server->getEventDispatcher(); |
453 | - $dispatcher->addListener('\OC\Repair::warning', function ($event) { |
|
453 | + $dispatcher->addListener('\OC\Repair::warning', function($event) { |
|
454 | 454 | if ($event instanceof GenericEvent) { |
455 | 455 | $this->emit('\OC\Updater', 'repairWarning', $event->getArguments()); |
456 | 456 | } |
457 | 457 | }); |
458 | - $dispatcher->addListener('\OC\Repair::error', function ($event) { |
|
458 | + $dispatcher->addListener('\OC\Repair::error', function($event) { |
|
459 | 459 | if ($event instanceof GenericEvent) { |
460 | 460 | $this->emit('\OC\Updater', 'repairError', $event->getArguments()); |
461 | 461 | } |
462 | 462 | }); |
463 | - $dispatcher->addListener('\OC\Repair::info', function ($event) { |
|
463 | + $dispatcher->addListener('\OC\Repair::info', function($event) { |
|
464 | 464 | if ($event instanceof GenericEvent) { |
465 | 465 | $this->emit('\OC\Updater', 'repairInfo', $event->getArguments()); |
466 | 466 | } |
467 | 467 | }); |
468 | - $dispatcher->addListener('\OC\Repair::step', function ($event) { |
|
468 | + $dispatcher->addListener('\OC\Repair::step', function($event) { |
|
469 | 469 | if ($event instanceof GenericEvent) { |
470 | 470 | $this->emit('\OC\Updater', 'repairStep', $event->getArguments()); |
471 | 471 | } |
@@ -480,13 +480,13 @@ discard block |
||
480 | 480 | if (!$event instanceof GenericEvent) { |
481 | 481 | return; |
482 | 482 | } |
483 | - $log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']); |
|
483 | + $log->info('\OC\DB\Migrator::executeSql: '.$event->getSubject().' ('.$event->getArgument(0).' of '.$event->getArgument(1).')', ['app' => 'updater']); |
|
484 | 484 | }); |
485 | 485 | $dispatcher->addListener('\OC\DB\Migrator::checkTable', function($event) use ($log) { |
486 | 486 | if (!$event instanceof GenericEvent) { |
487 | 487 | return; |
488 | 488 | } |
489 | - $log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']); |
|
489 | + $log->info('\OC\DB\Migrator::checkTable: '.$event->getSubject().' ('.$event->getArgument(0).' of '.$event->getArgument(1).')', ['app' => 'updater']); |
|
490 | 490 | }); |
491 | 491 | |
492 | 492 | $repairListener = function($event) use ($log) { |
@@ -495,30 +495,30 @@ discard block |
||
495 | 495 | } |
496 | 496 | switch ($event->getSubject()) { |
497 | 497 | case '\OC\Repair::startProgress': |
498 | - $log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']); |
|
498 | + $log->info('\OC\Repair::startProgress: Starting ... '.$event->getArgument(1).' ('.$event->getArgument(0).')', ['app' => 'updater']); |
|
499 | 499 | break; |
500 | 500 | case '\OC\Repair::advance': |
501 | 501 | $desc = $event->getArgument(1); |
502 | 502 | if (empty($desc)) { |
503 | 503 | $desc = ''; |
504 | 504 | } |
505 | - $log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']); |
|
505 | + $log->info('\OC\Repair::advance: '.$desc.' ('.$event->getArgument(0).')', ['app' => 'updater']); |
|
506 | 506 | |
507 | 507 | break; |
508 | 508 | case '\OC\Repair::finishProgress': |
509 | 509 | $log->info('\OC\Repair::finishProgress', ['app' => 'updater']); |
510 | 510 | break; |
511 | 511 | case '\OC\Repair::step': |
512 | - $log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']); |
|
512 | + $log->info('\OC\Repair::step: Repair step: '.$event->getArgument(0), ['app' => 'updater']); |
|
513 | 513 | break; |
514 | 514 | case '\OC\Repair::info': |
515 | - $log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']); |
|
515 | + $log->info('\OC\Repair::info: Repair info: '.$event->getArgument(0), ['app' => 'updater']); |
|
516 | 516 | break; |
517 | 517 | case '\OC\Repair::warning': |
518 | - $log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']); |
|
518 | + $log->warning('\OC\Repair::warning: Repair warning: '.$event->getArgument(0), ['app' => 'updater']); |
|
519 | 519 | break; |
520 | 520 | case '\OC\Repair::error': |
521 | - $log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']); |
|
521 | + $log->error('\OC\Repair::error: Repair error: '.$event->getArgument(0), ['app' => 'updater']); |
|
522 | 522 | break; |
523 | 523 | } |
524 | 524 | }; |
@@ -532,74 +532,74 @@ discard block |
||
532 | 532 | $dispatcher->addListener('\OC\Repair::error', $repairListener); |
533 | 533 | |
534 | 534 | |
535 | - $this->listen('\OC\Updater', 'maintenanceEnabled', function () use($log) { |
|
535 | + $this->listen('\OC\Updater', 'maintenanceEnabled', function() use($log) { |
|
536 | 536 | $log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']); |
537 | 537 | }); |
538 | - $this->listen('\OC\Updater', 'maintenanceDisabled', function () use($log) { |
|
538 | + $this->listen('\OC\Updater', 'maintenanceDisabled', function() use($log) { |
|
539 | 539 | $log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']); |
540 | 540 | }); |
541 | - $this->listen('\OC\Updater', 'maintenanceActive', function () use($log) { |
|
541 | + $this->listen('\OC\Updater', 'maintenanceActive', function() use($log) { |
|
542 | 542 | $log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']); |
543 | 543 | }); |
544 | - $this->listen('\OC\Updater', 'updateEnd', function ($success) use($log) { |
|
544 | + $this->listen('\OC\Updater', 'updateEnd', function($success) use($log) { |
|
545 | 545 | if ($success) { |
546 | 546 | $log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']); |
547 | 547 | } else { |
548 | 548 | $log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']); |
549 | 549 | } |
550 | 550 | }); |
551 | - $this->listen('\OC\Updater', 'dbUpgradeBefore', function () use($log) { |
|
551 | + $this->listen('\OC\Updater', 'dbUpgradeBefore', function() use($log) { |
|
552 | 552 | $log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']); |
553 | 553 | }); |
554 | - $this->listen('\OC\Updater', 'dbUpgrade', function () use($log) { |
|
554 | + $this->listen('\OC\Updater', 'dbUpgrade', function() use($log) { |
|
555 | 555 | $log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']); |
556 | 556 | }); |
557 | - $this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use($log) { |
|
557 | + $this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function() use($log) { |
|
558 | 558 | $log->info('\OC\Updater::dbSimulateUpgradeBefore: Checking whether the database schema can be updated (this can take a long time depending on the database size)', ['app' => 'updater']); |
559 | 559 | }); |
560 | - $this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use($log) { |
|
560 | + $this->listen('\OC\Updater', 'dbSimulateUpgrade', function() use($log) { |
|
561 | 561 | $log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']); |
562 | 562 | }); |
563 | - $this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use($log) { |
|
564 | - $log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']); |
|
563 | + $this->listen('\OC\Updater', 'incompatibleAppDisabled', function($app) use($log) { |
|
564 | + $log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: '.$app, ['app' => 'updater']); |
|
565 | 565 | }); |
566 | - $this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use($log) { |
|
567 | - $log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']); |
|
566 | + $this->listen('\OC\Updater', 'checkAppStoreAppBefore', function($app) use($log) { |
|
567 | + $log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "'.$app.'" in appstore', ['app' => 'updater']); |
|
568 | 568 | }); |
569 | - $this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use($log) { |
|
570 | - $log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']); |
|
569 | + $this->listen('\OC\Updater', 'upgradeAppStoreApp', function($app) use($log) { |
|
570 | + $log->info('\OC\Updater::upgradeAppStoreApp: Update app "'.$app.'" from appstore', ['app' => 'updater']); |
|
571 | 571 | }); |
572 | - $this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use($log) { |
|
573 | - $log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']); |
|
572 | + $this->listen('\OC\Updater', 'checkAppStoreApp', function($app) use($log) { |
|
573 | + $log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "'.$app.'" in appstore', ['app' => 'updater']); |
|
574 | 574 | }); |
575 | - $this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) { |
|
575 | + $this->listen('\OC\Updater', 'appUpgradeCheckBefore', function() use ($log) { |
|
576 | 576 | $log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']); |
577 | 577 | }); |
578 | - $this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) { |
|
579 | - $log->info('\OC\Updater::appSimulateUpdate: Checking whether the database schema for <' . $app . '> can be updated (this can take a long time depending on the database size)', ['app' => 'updater']); |
|
578 | + $this->listen('\OC\Updater', 'appSimulateUpdate', function($app) use ($log) { |
|
579 | + $log->info('\OC\Updater::appSimulateUpdate: Checking whether the database schema for <'.$app.'> can be updated (this can take a long time depending on the database size)', ['app' => 'updater']); |
|
580 | 580 | }); |
581 | - $this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) { |
|
581 | + $this->listen('\OC\Updater', 'appUpgradeCheck', function() use ($log) { |
|
582 | 582 | $log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']); |
583 | 583 | }); |
584 | - $this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) { |
|
585 | - $log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']); |
|
584 | + $this->listen('\OC\Updater', 'appUpgradeStarted', function($app) use ($log) { |
|
585 | + $log->info('\OC\Updater::appUpgradeStarted: Updating <'.$app.'> ...', ['app' => 'updater']); |
|
586 | 586 | }); |
587 | - $this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) { |
|
588 | - $log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']); |
|
587 | + $this->listen('\OC\Updater', 'appUpgrade', function($app, $version) use ($log) { |
|
588 | + $log->info('\OC\Updater::appUpgrade: Updated <'.$app.'> to '.$version, ['app' => 'updater']); |
|
589 | 589 | }); |
590 | - $this->listen('\OC\Updater', 'failure', function ($message) use($log) { |
|
591 | - $log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']); |
|
590 | + $this->listen('\OC\Updater', 'failure', function($message) use($log) { |
|
591 | + $log->error('\OC\Updater::failure: '.$message, ['app' => 'updater']); |
|
592 | 592 | }); |
593 | - $this->listen('\OC\Updater', 'setDebugLogLevel', function () use($log) { |
|
593 | + $this->listen('\OC\Updater', 'setDebugLogLevel', function() use($log) { |
|
594 | 594 | $log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']); |
595 | 595 | }); |
596 | - $this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($log) { |
|
597 | - $log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']); |
|
596 | + $this->listen('\OC\Updater', 'resetLogLevel', function($logLevel, $logLevelName) use($log) { |
|
597 | + $log->info('\OC\Updater::resetLogLevel: Reset log level to '.$logLevelName.'('.$logLevel.')', ['app' => 'updater']); |
|
598 | 598 | }); |
599 | - $this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($log) { |
|
599 | + $this->listen('\OC\Updater', 'startCheckCodeIntegrity', function() use($log) { |
|
600 | 600 | $log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']); |
601 | 601 | }); |
602 | - $this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($log) { |
|
602 | + $this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function() use($log) { |
|
603 | 603 | $log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']); |
604 | 604 | }); |
605 | 605 |
@@ -35,170 +35,170 @@ |
||
35 | 35 | |
36 | 36 | class File implements ICache { |
37 | 37 | |
38 | - /** @var View */ |
|
39 | - protected $storage; |
|
38 | + /** @var View */ |
|
39 | + protected $storage; |
|
40 | 40 | |
41 | - /** |
|
42 | - * Returns the cache storage for the logged in user |
|
43 | - * |
|
44 | - * @return \OC\Files\View cache storage |
|
45 | - * @throws \OC\ForbiddenException |
|
46 | - * @throws \OC\User\NoUserException |
|
47 | - */ |
|
48 | - protected function getStorage() { |
|
49 | - if (isset($this->storage)) { |
|
50 | - return $this->storage; |
|
51 | - } |
|
52 | - if (\OC::$server->getUserSession()->isLoggedIn()) { |
|
53 | - $rootView = new View(); |
|
54 | - $user = \OC::$server->getUserSession()->getUser(); |
|
55 | - Filesystem::initMountPoints($user->getUID()); |
|
56 | - if (!$rootView->file_exists('/' . $user->getUID() . '/cache')) { |
|
57 | - $rootView->mkdir('/' . $user->getUID() . '/cache'); |
|
58 | - } |
|
59 | - $this->storage = new View('/' . $user->getUID() . '/cache'); |
|
60 | - return $this->storage; |
|
61 | - } else { |
|
62 | - \OCP\Util::writeLog('core', 'Can\'t get cache storage, user not logged in', ILogger::ERROR); |
|
63 | - throw new \OC\ForbiddenException('Can\t get cache storage, user not logged in'); |
|
64 | - } |
|
65 | - } |
|
41 | + /** |
|
42 | + * Returns the cache storage for the logged in user |
|
43 | + * |
|
44 | + * @return \OC\Files\View cache storage |
|
45 | + * @throws \OC\ForbiddenException |
|
46 | + * @throws \OC\User\NoUserException |
|
47 | + */ |
|
48 | + protected function getStorage() { |
|
49 | + if (isset($this->storage)) { |
|
50 | + return $this->storage; |
|
51 | + } |
|
52 | + if (\OC::$server->getUserSession()->isLoggedIn()) { |
|
53 | + $rootView = new View(); |
|
54 | + $user = \OC::$server->getUserSession()->getUser(); |
|
55 | + Filesystem::initMountPoints($user->getUID()); |
|
56 | + if (!$rootView->file_exists('/' . $user->getUID() . '/cache')) { |
|
57 | + $rootView->mkdir('/' . $user->getUID() . '/cache'); |
|
58 | + } |
|
59 | + $this->storage = new View('/' . $user->getUID() . '/cache'); |
|
60 | + return $this->storage; |
|
61 | + } else { |
|
62 | + \OCP\Util::writeLog('core', 'Can\'t get cache storage, user not logged in', ILogger::ERROR); |
|
63 | + throw new \OC\ForbiddenException('Can\t get cache storage, user not logged in'); |
|
64 | + } |
|
65 | + } |
|
66 | 66 | |
67 | - /** |
|
68 | - * @param string $key |
|
69 | - * @return mixed|null |
|
70 | - * @throws \OC\ForbiddenException |
|
71 | - */ |
|
72 | - public function get($key) { |
|
73 | - $result = null; |
|
74 | - if ($this->hasKey($key)) { |
|
75 | - $storage = $this->getStorage(); |
|
76 | - $result = $storage->file_get_contents($key); |
|
77 | - } |
|
78 | - return $result; |
|
79 | - } |
|
67 | + /** |
|
68 | + * @param string $key |
|
69 | + * @return mixed|null |
|
70 | + * @throws \OC\ForbiddenException |
|
71 | + */ |
|
72 | + public function get($key) { |
|
73 | + $result = null; |
|
74 | + if ($this->hasKey($key)) { |
|
75 | + $storage = $this->getStorage(); |
|
76 | + $result = $storage->file_get_contents($key); |
|
77 | + } |
|
78 | + return $result; |
|
79 | + } |
|
80 | 80 | |
81 | - /** |
|
82 | - * Returns the size of the stored/cached data |
|
83 | - * |
|
84 | - * @param string $key |
|
85 | - * @return int |
|
86 | - */ |
|
87 | - public function size($key) { |
|
88 | - $result = 0; |
|
89 | - if ($this->hasKey($key)) { |
|
90 | - $storage = $this->getStorage(); |
|
91 | - $result = $storage->filesize($key); |
|
92 | - } |
|
93 | - return $result; |
|
94 | - } |
|
81 | + /** |
|
82 | + * Returns the size of the stored/cached data |
|
83 | + * |
|
84 | + * @param string $key |
|
85 | + * @return int |
|
86 | + */ |
|
87 | + public function size($key) { |
|
88 | + $result = 0; |
|
89 | + if ($this->hasKey($key)) { |
|
90 | + $storage = $this->getStorage(); |
|
91 | + $result = $storage->filesize($key); |
|
92 | + } |
|
93 | + return $result; |
|
94 | + } |
|
95 | 95 | |
96 | - /** |
|
97 | - * @param string $key |
|
98 | - * @param mixed $value |
|
99 | - * @param int $ttl |
|
100 | - * @return bool|mixed |
|
101 | - * @throws \OC\ForbiddenException |
|
102 | - */ |
|
103 | - public function set($key, $value, $ttl = 0) { |
|
104 | - $storage = $this->getStorage(); |
|
105 | - $result = false; |
|
106 | - // unique id to avoid chunk collision, just in case |
|
107 | - $uniqueId = \OC::$server->getSecureRandom()->generate( |
|
108 | - 16, |
|
109 | - ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER |
|
110 | - ); |
|
96 | + /** |
|
97 | + * @param string $key |
|
98 | + * @param mixed $value |
|
99 | + * @param int $ttl |
|
100 | + * @return bool|mixed |
|
101 | + * @throws \OC\ForbiddenException |
|
102 | + */ |
|
103 | + public function set($key, $value, $ttl = 0) { |
|
104 | + $storage = $this->getStorage(); |
|
105 | + $result = false; |
|
106 | + // unique id to avoid chunk collision, just in case |
|
107 | + $uniqueId = \OC::$server->getSecureRandom()->generate( |
|
108 | + 16, |
|
109 | + ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER |
|
110 | + ); |
|
111 | 111 | |
112 | - // use part file to prevent hasKey() to find the key |
|
113 | - // while it is being written |
|
114 | - $keyPart = $key . '.' . $uniqueId . '.part'; |
|
115 | - if ($storage and $storage->file_put_contents($keyPart, $value)) { |
|
116 | - if ($ttl === 0) { |
|
117 | - $ttl = 86400; // 60*60*24 |
|
118 | - } |
|
119 | - $result = $storage->touch($keyPart, time() + $ttl); |
|
120 | - $result &= $storage->rename($keyPart, $key); |
|
121 | - } |
|
122 | - return $result; |
|
123 | - } |
|
112 | + // use part file to prevent hasKey() to find the key |
|
113 | + // while it is being written |
|
114 | + $keyPart = $key . '.' . $uniqueId . '.part'; |
|
115 | + if ($storage and $storage->file_put_contents($keyPart, $value)) { |
|
116 | + if ($ttl === 0) { |
|
117 | + $ttl = 86400; // 60*60*24 |
|
118 | + } |
|
119 | + $result = $storage->touch($keyPart, time() + $ttl); |
|
120 | + $result &= $storage->rename($keyPart, $key); |
|
121 | + } |
|
122 | + return $result; |
|
123 | + } |
|
124 | 124 | |
125 | - /** |
|
126 | - * @param string $key |
|
127 | - * @return bool |
|
128 | - * @throws \OC\ForbiddenException |
|
129 | - */ |
|
130 | - public function hasKey($key) { |
|
131 | - $storage = $this->getStorage(); |
|
132 | - if ($storage && $storage->is_file($key) && $storage->isReadable($key)) { |
|
133 | - return true; |
|
134 | - } |
|
135 | - return false; |
|
136 | - } |
|
125 | + /** |
|
126 | + * @param string $key |
|
127 | + * @return bool |
|
128 | + * @throws \OC\ForbiddenException |
|
129 | + */ |
|
130 | + public function hasKey($key) { |
|
131 | + $storage = $this->getStorage(); |
|
132 | + if ($storage && $storage->is_file($key) && $storage->isReadable($key)) { |
|
133 | + return true; |
|
134 | + } |
|
135 | + return false; |
|
136 | + } |
|
137 | 137 | |
138 | - /** |
|
139 | - * @param string $key |
|
140 | - * @return bool|mixed |
|
141 | - * @throws \OC\ForbiddenException |
|
142 | - */ |
|
143 | - public function remove($key) { |
|
144 | - $storage = $this->getStorage(); |
|
145 | - if (!$storage) { |
|
146 | - return false; |
|
147 | - } |
|
148 | - return $storage->unlink($key); |
|
149 | - } |
|
138 | + /** |
|
139 | + * @param string $key |
|
140 | + * @return bool|mixed |
|
141 | + * @throws \OC\ForbiddenException |
|
142 | + */ |
|
143 | + public function remove($key) { |
|
144 | + $storage = $this->getStorage(); |
|
145 | + if (!$storage) { |
|
146 | + return false; |
|
147 | + } |
|
148 | + return $storage->unlink($key); |
|
149 | + } |
|
150 | 150 | |
151 | - /** |
|
152 | - * @param string $prefix |
|
153 | - * @return bool |
|
154 | - * @throws \OC\ForbiddenException |
|
155 | - */ |
|
156 | - public function clear($prefix = '') { |
|
157 | - $storage = $this->getStorage(); |
|
158 | - if ($storage and $storage->is_dir('/')) { |
|
159 | - $dh = $storage->opendir('/'); |
|
160 | - if (is_resource($dh)) { |
|
161 | - while (($file = readdir($dh)) !== false) { |
|
162 | - if ($file != '.' and $file != '..' and ($prefix === '' || strpos($file, $prefix) === 0)) { |
|
163 | - $storage->unlink('/' . $file); |
|
164 | - } |
|
165 | - } |
|
166 | - } |
|
167 | - } |
|
168 | - return true; |
|
169 | - } |
|
151 | + /** |
|
152 | + * @param string $prefix |
|
153 | + * @return bool |
|
154 | + * @throws \OC\ForbiddenException |
|
155 | + */ |
|
156 | + public function clear($prefix = '') { |
|
157 | + $storage = $this->getStorage(); |
|
158 | + if ($storage and $storage->is_dir('/')) { |
|
159 | + $dh = $storage->opendir('/'); |
|
160 | + if (is_resource($dh)) { |
|
161 | + while (($file = readdir($dh)) !== false) { |
|
162 | + if ($file != '.' and $file != '..' and ($prefix === '' || strpos($file, $prefix) === 0)) { |
|
163 | + $storage->unlink('/' . $file); |
|
164 | + } |
|
165 | + } |
|
166 | + } |
|
167 | + } |
|
168 | + return true; |
|
169 | + } |
|
170 | 170 | |
171 | - /** |
|
172 | - * Runs GC |
|
173 | - * @throws \OC\ForbiddenException |
|
174 | - */ |
|
175 | - public function gc() { |
|
176 | - $storage = $this->getStorage(); |
|
177 | - if ($storage and $storage->is_dir('/')) { |
|
178 | - // extra hour safety, in case of stray part chunks that take longer to write, |
|
179 | - // because touch() is only called after the chunk was finished |
|
180 | - $now = time() - 3600; |
|
181 | - $dh = $storage->opendir('/'); |
|
182 | - if (!is_resource($dh)) { |
|
183 | - return null; |
|
184 | - } |
|
185 | - while (($file = readdir($dh)) !== false) { |
|
186 | - if ($file != '.' and $file != '..') { |
|
187 | - try { |
|
188 | - $mtime = $storage->filemtime('/' . $file); |
|
189 | - if ($mtime < $now) { |
|
190 | - $storage->unlink('/' . $file); |
|
191 | - } |
|
192 | - } catch (\OCP\Lock\LockedException $e) { |
|
193 | - // ignore locked chunks |
|
194 | - \OC::$server->getLogger()->debug('Could not cleanup locked chunk "' . $file . '"', array('app' => 'core')); |
|
195 | - } catch (\OCP\Files\ForbiddenException $e) { |
|
196 | - \OC::$server->getLogger()->debug('Could not cleanup forbidden chunk "' . $file . '"', array('app' => 'core')); |
|
197 | - } catch (\OCP\Files\LockNotAcquiredException $e) { |
|
198 | - \OC::$server->getLogger()->debug('Could not cleanup locked chunk "' . $file . '"', array('app' => 'core')); |
|
199 | - } |
|
200 | - } |
|
201 | - } |
|
202 | - } |
|
203 | - } |
|
171 | + /** |
|
172 | + * Runs GC |
|
173 | + * @throws \OC\ForbiddenException |
|
174 | + */ |
|
175 | + public function gc() { |
|
176 | + $storage = $this->getStorage(); |
|
177 | + if ($storage and $storage->is_dir('/')) { |
|
178 | + // extra hour safety, in case of stray part chunks that take longer to write, |
|
179 | + // because touch() is only called after the chunk was finished |
|
180 | + $now = time() - 3600; |
|
181 | + $dh = $storage->opendir('/'); |
|
182 | + if (!is_resource($dh)) { |
|
183 | + return null; |
|
184 | + } |
|
185 | + while (($file = readdir($dh)) !== false) { |
|
186 | + if ($file != '.' and $file != '..') { |
|
187 | + try { |
|
188 | + $mtime = $storage->filemtime('/' . $file); |
|
189 | + if ($mtime < $now) { |
|
190 | + $storage->unlink('/' . $file); |
|
191 | + } |
|
192 | + } catch (\OCP\Lock\LockedException $e) { |
|
193 | + // ignore locked chunks |
|
194 | + \OC::$server->getLogger()->debug('Could not cleanup locked chunk "' . $file . '"', array('app' => 'core')); |
|
195 | + } catch (\OCP\Files\ForbiddenException $e) { |
|
196 | + \OC::$server->getLogger()->debug('Could not cleanup forbidden chunk "' . $file . '"', array('app' => 'core')); |
|
197 | + } catch (\OCP\Files\LockNotAcquiredException $e) { |
|
198 | + \OC::$server->getLogger()->debug('Could not cleanup locked chunk "' . $file . '"', array('app' => 'core')); |
|
199 | + } |
|
200 | + } |
|
201 | + } |
|
202 | + } |
|
203 | + } |
|
204 | 204 | } |
@@ -53,10 +53,10 @@ discard block |
||
53 | 53 | $rootView = new View(); |
54 | 54 | $user = \OC::$server->getUserSession()->getUser(); |
55 | 55 | Filesystem::initMountPoints($user->getUID()); |
56 | - if (!$rootView->file_exists('/' . $user->getUID() . '/cache')) { |
|
57 | - $rootView->mkdir('/' . $user->getUID() . '/cache'); |
|
56 | + if (!$rootView->file_exists('/'.$user->getUID().'/cache')) { |
|
57 | + $rootView->mkdir('/'.$user->getUID().'/cache'); |
|
58 | 58 | } |
59 | - $this->storage = new View('/' . $user->getUID() . '/cache'); |
|
59 | + $this->storage = new View('/'.$user->getUID().'/cache'); |
|
60 | 60 | return $this->storage; |
61 | 61 | } else { |
62 | 62 | \OCP\Util::writeLog('core', 'Can\'t get cache storage, user not logged in', ILogger::ERROR); |
@@ -106,12 +106,12 @@ discard block |
||
106 | 106 | // unique id to avoid chunk collision, just in case |
107 | 107 | $uniqueId = \OC::$server->getSecureRandom()->generate( |
108 | 108 | 16, |
109 | - ISecureRandom::CHAR_DIGITS . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER |
|
109 | + ISecureRandom::CHAR_DIGITS.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_UPPER |
|
110 | 110 | ); |
111 | 111 | |
112 | 112 | // use part file to prevent hasKey() to find the key |
113 | 113 | // while it is being written |
114 | - $keyPart = $key . '.' . $uniqueId . '.part'; |
|
114 | + $keyPart = $key.'.'.$uniqueId.'.part'; |
|
115 | 115 | if ($storage and $storage->file_put_contents($keyPart, $value)) { |
116 | 116 | if ($ttl === 0) { |
117 | 117 | $ttl = 86400; // 60*60*24 |
@@ -160,7 +160,7 @@ discard block |
||
160 | 160 | if (is_resource($dh)) { |
161 | 161 | while (($file = readdir($dh)) !== false) { |
162 | 162 | if ($file != '.' and $file != '..' and ($prefix === '' || strpos($file, $prefix) === 0)) { |
163 | - $storage->unlink('/' . $file); |
|
163 | + $storage->unlink('/'.$file); |
|
164 | 164 | } |
165 | 165 | } |
166 | 166 | } |
@@ -185,17 +185,17 @@ discard block |
||
185 | 185 | while (($file = readdir($dh)) !== false) { |
186 | 186 | if ($file != '.' and $file != '..') { |
187 | 187 | try { |
188 | - $mtime = $storage->filemtime('/' . $file); |
|
188 | + $mtime = $storage->filemtime('/'.$file); |
|
189 | 189 | if ($mtime < $now) { |
190 | - $storage->unlink('/' . $file); |
|
190 | + $storage->unlink('/'.$file); |
|
191 | 191 | } |
192 | 192 | } catch (\OCP\Lock\LockedException $e) { |
193 | 193 | // ignore locked chunks |
194 | - \OC::$server->getLogger()->debug('Could not cleanup locked chunk "' . $file . '"', array('app' => 'core')); |
|
194 | + \OC::$server->getLogger()->debug('Could not cleanup locked chunk "'.$file.'"', array('app' => 'core')); |
|
195 | 195 | } catch (\OCP\Files\ForbiddenException $e) { |
196 | - \OC::$server->getLogger()->debug('Could not cleanup forbidden chunk "' . $file . '"', array('app' => 'core')); |
|
196 | + \OC::$server->getLogger()->debug('Could not cleanup forbidden chunk "'.$file.'"', array('app' => 'core')); |
|
197 | 197 | } catch (\OCP\Files\LockNotAcquiredException $e) { |
198 | - \OC::$server->getLogger()->debug('Could not cleanup locked chunk "' . $file . '"', array('app' => 'core')); |
|
198 | + \OC::$server->getLogger()->debug('Could not cleanup locked chunk "'.$file.'"', array('app' => 'core')); |
|
199 | 199 | } |
200 | 200 | } |
201 | 201 | } |
@@ -76,384 +76,384 @@ |
||
76 | 76 | * Class for user management in a SQL Database (e.g. MySQL, SQLite) |
77 | 77 | */ |
78 | 78 | class Database extends ABackend |
79 | - implements ICreateUserBackend, |
|
80 | - ISetPasswordBackend, |
|
81 | - ISetDisplayNameBackend, |
|
82 | - IGetDisplayNameBackend, |
|
83 | - ICheckPasswordBackend, |
|
84 | - IGetHomeBackend, |
|
85 | - ICountUsersBackend { |
|
86 | - /** @var CappedMemoryCache */ |
|
87 | - private $cache; |
|
88 | - |
|
89 | - /** @var EventDispatcher */ |
|
90 | - private $eventDispatcher; |
|
91 | - |
|
92 | - /** @var IDBConnection */ |
|
93 | - private $dbConn; |
|
94 | - |
|
95 | - /** |
|
96 | - * \OC\User\Database constructor. |
|
97 | - * |
|
98 | - * @param EventDispatcher $eventDispatcher |
|
99 | - */ |
|
100 | - public function __construct($eventDispatcher = null) { |
|
101 | - $this->cache = new CappedMemoryCache(); |
|
102 | - $this->eventDispatcher = $eventDispatcher ? $eventDispatcher : \OC::$server->getEventDispatcher(); |
|
103 | - } |
|
104 | - |
|
105 | - /** |
|
106 | - * FIXME: This function should not be required! |
|
107 | - */ |
|
108 | - private function fixDI() { |
|
109 | - if ($this->dbConn === null) { |
|
110 | - $this->dbConn = \OC::$server->getDatabaseConnection(); |
|
111 | - } |
|
112 | - } |
|
113 | - |
|
114 | - /** |
|
115 | - * Create a new user |
|
116 | - * |
|
117 | - * @param string $uid The username of the user to create |
|
118 | - * @param string $password The password of the new user |
|
119 | - * @return bool |
|
120 | - * |
|
121 | - * Creates a new user. Basic checking of username is done in OC_User |
|
122 | - * itself, not in its subclasses. |
|
123 | - */ |
|
124 | - public function createUser(string $uid, string $password): bool { |
|
125 | - $this->fixDI(); |
|
126 | - |
|
127 | - if (!$this->userExists($uid)) { |
|
128 | - $event = new GenericEvent($password); |
|
129 | - $this->eventDispatcher->dispatch('OCP\PasswordPolicy::validate', $event); |
|
130 | - |
|
131 | - $qb = $this->dbConn->getQueryBuilder(); |
|
132 | - $qb->insert('users') |
|
133 | - ->values([ |
|
134 | - 'uid' => $qb->createNamedParameter($uid), |
|
135 | - 'password' => $qb->createNamedParameter(\OC::$server->getHasher()->hash($password)), |
|
136 | - 'uid_lower' => $qb->createNamedParameter(mb_strtolower($uid)), |
|
137 | - ]); |
|
138 | - |
|
139 | - $result = $qb->execute(); |
|
140 | - |
|
141 | - // Clear cache |
|
142 | - unset($this->cache[$uid]); |
|
143 | - |
|
144 | - return $result ? true : false; |
|
145 | - } |
|
146 | - |
|
147 | - return false; |
|
148 | - } |
|
149 | - |
|
150 | - /** |
|
151 | - * delete a user |
|
152 | - * |
|
153 | - * @param string $uid The username of the user to delete |
|
154 | - * @return bool |
|
155 | - * |
|
156 | - * Deletes a user |
|
157 | - */ |
|
158 | - public function deleteUser($uid) { |
|
159 | - $this->fixDI(); |
|
160 | - |
|
161 | - // Delete user-group-relation |
|
162 | - $query = \OC_DB::prepare('DELETE FROM `*PREFIX*users` WHERE `uid` = ?'); |
|
163 | - $result = $query->execute([$uid]); |
|
164 | - |
|
165 | - if (isset($this->cache[$uid])) { |
|
166 | - unset($this->cache[$uid]); |
|
167 | - } |
|
168 | - |
|
169 | - return $result ? true : false; |
|
170 | - } |
|
171 | - |
|
172 | - /** |
|
173 | - * Set password |
|
174 | - * |
|
175 | - * @param string $uid The username |
|
176 | - * @param string $password The new password |
|
177 | - * @return bool |
|
178 | - * |
|
179 | - * Change the password of a user |
|
180 | - */ |
|
181 | - public function setPassword(string $uid, string $password): bool { |
|
182 | - $this->fixDI(); |
|
183 | - |
|
184 | - if ($this->userExists($uid)) { |
|
185 | - $event = new GenericEvent($password); |
|
186 | - $this->eventDispatcher->dispatch('OCP\PasswordPolicy::validate', $event); |
|
187 | - $query = \OC_DB::prepare('UPDATE `*PREFIX*users` SET `password` = ? WHERE `uid` = ?'); |
|
188 | - $result = $query->execute([\OC::$server->getHasher()->hash($password), $uid]); |
|
189 | - |
|
190 | - return $result ? true : false; |
|
191 | - } |
|
192 | - |
|
193 | - return false; |
|
194 | - } |
|
195 | - |
|
196 | - /** |
|
197 | - * Set display name |
|
198 | - * |
|
199 | - * @param string $uid The username |
|
200 | - * @param string $displayName The new display name |
|
201 | - * @return bool |
|
202 | - * |
|
203 | - * Change the display name of a user |
|
204 | - */ |
|
205 | - public function setDisplayName(string $uid, string $displayName): bool { |
|
206 | - $this->fixDI(); |
|
207 | - |
|
208 | - if ($this->userExists($uid)) { |
|
209 | - $query = \OC_DB::prepare('UPDATE `*PREFIX*users` SET `displayname` = ? WHERE LOWER(`uid`) = LOWER(?)'); |
|
210 | - $query->execute([$displayName, $uid]); |
|
211 | - $this->cache[$uid]['displayname'] = $displayName; |
|
212 | - |
|
213 | - return true; |
|
214 | - } |
|
215 | - |
|
216 | - return false; |
|
217 | - } |
|
218 | - |
|
219 | - /** |
|
220 | - * get display name of the user |
|
221 | - * |
|
222 | - * @param string $uid user ID of the user |
|
223 | - * @return string display name |
|
224 | - */ |
|
225 | - public function getDisplayName($uid): string { |
|
226 | - $uid = (string)$uid; |
|
227 | - $this->loadUser($uid); |
|
228 | - return empty($this->cache[$uid]['displayname']) ? $uid : $this->cache[$uid]['displayname']; |
|
229 | - } |
|
230 | - |
|
231 | - /** |
|
232 | - * Get a list of all display names and user ids. |
|
233 | - * |
|
234 | - * @param string $search |
|
235 | - * @param string|null $limit |
|
236 | - * @param string|null $offset |
|
237 | - * @return array an array of all displayNames (value) and the corresponding uids (key) |
|
238 | - */ |
|
239 | - public function getDisplayNames($search = '', $limit = null, $offset = null) { |
|
240 | - $this->fixDI(); |
|
241 | - |
|
242 | - $query = $this->dbConn->getQueryBuilder(); |
|
243 | - |
|
244 | - $query->select('uid', 'displayname') |
|
245 | - ->from('users', 'u') |
|
246 | - ->leftJoin('u', 'preferences', 'p', $query->expr()->andX( |
|
247 | - $query->expr()->eq('userid', 'uid'), |
|
248 | - $query->expr()->eq('appid', $query->expr()->literal('settings')), |
|
249 | - $query->expr()->eq('configkey', $query->expr()->literal('email'))) |
|
250 | - ) |
|
251 | - // sqlite doesn't like re-using a single named parameter here |
|
252 | - ->where($query->expr()->iLike('uid', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%'))) |
|
253 | - ->orWhere($query->expr()->iLike('displayname', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%'))) |
|
254 | - ->orWhere($query->expr()->iLike('configvalue', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%'))) |
|
255 | - ->orderBy($query->func()->lower('displayname'), 'ASC') |
|
256 | - ->orderBy($query->func()->lower('uid'), 'ASC') |
|
257 | - ->setMaxResults($limit) |
|
258 | - ->setFirstResult($offset); |
|
259 | - |
|
260 | - $result = $query->execute(); |
|
261 | - $displayNames = []; |
|
262 | - while ($row = $result->fetch()) { |
|
263 | - $displayNames[(string)$row['uid']] = (string)$row['displayname']; |
|
264 | - } |
|
265 | - |
|
266 | - return $displayNames; |
|
267 | - } |
|
268 | - |
|
269 | - /** |
|
270 | - * Check if the password is correct |
|
271 | - * |
|
272 | - * @param string $uid The username |
|
273 | - * @param string $password The password |
|
274 | - * @return string |
|
275 | - * |
|
276 | - * Check if the password is correct without logging in the user |
|
277 | - * returns the user id or false |
|
278 | - */ |
|
279 | - public function checkPassword(string $uid, string $password) { |
|
280 | - $this->fixDI(); |
|
281 | - |
|
282 | - $qb = $this->dbConn->getQueryBuilder(); |
|
283 | - $qb->select('uid', 'password') |
|
284 | - ->from('users') |
|
285 | - ->where( |
|
286 | - $qb->expr()->eq( |
|
287 | - 'uid_lower', $qb->createNamedParameter(mb_strtolower($uid)) |
|
288 | - ) |
|
289 | - ); |
|
290 | - $result = $qb->execute(); |
|
291 | - $row = $result->fetch(); |
|
292 | - $result->closeCursor(); |
|
293 | - |
|
294 | - if ($row) { |
|
295 | - $storedHash = $row['password']; |
|
296 | - $newHash = ''; |
|
297 | - if (\OC::$server->getHasher()->verify($password, $storedHash, $newHash)) { |
|
298 | - if (!empty($newHash)) { |
|
299 | - $this->setPassword($uid, $password); |
|
300 | - } |
|
301 | - return (string)$row['uid']; |
|
302 | - } |
|
303 | - |
|
304 | - } |
|
305 | - |
|
306 | - return false; |
|
307 | - } |
|
308 | - |
|
309 | - /** |
|
310 | - * Load an user in the cache |
|
311 | - * |
|
312 | - * @param string $uid the username |
|
313 | - * @return boolean true if user was found, false otherwise |
|
314 | - */ |
|
315 | - private function loadUser($uid) { |
|
316 | - $this->fixDI(); |
|
317 | - |
|
318 | - $uid = (string)$uid; |
|
319 | - if (!isset($this->cache[$uid])) { |
|
320 | - //guests $uid could be NULL or '' |
|
321 | - if ($uid === '') { |
|
322 | - $this->cache[$uid] = false; |
|
323 | - return true; |
|
324 | - } |
|
325 | - |
|
326 | - $qb = $this->dbConn->getQueryBuilder(); |
|
327 | - $qb->select('uid', 'displayname') |
|
328 | - ->from('users') |
|
329 | - ->where( |
|
330 | - $qb->expr()->eq( |
|
331 | - 'uid_lower', $qb->createNamedParameter(mb_strtolower($uid)) |
|
332 | - ) |
|
333 | - ); |
|
334 | - $result = $qb->execute(); |
|
335 | - $row = $result->fetch(); |
|
336 | - $result->closeCursor(); |
|
337 | - |
|
338 | - $this->cache[$uid] = false; |
|
339 | - |
|
340 | - // "uid" is primary key, so there can only be a single result |
|
341 | - if ($row !== false) { |
|
342 | - $this->cache[$uid]['uid'] = (string)$row['uid']; |
|
343 | - $this->cache[$uid]['displayname'] = (string)$row['displayname']; |
|
344 | - } else { |
|
345 | - return false; |
|
346 | - } |
|
347 | - } |
|
348 | - |
|
349 | - return true; |
|
350 | - } |
|
351 | - |
|
352 | - /** |
|
353 | - * Get a list of all users |
|
354 | - * |
|
355 | - * @param string $search |
|
356 | - * @param null|int $limit |
|
357 | - * @param null|int $offset |
|
358 | - * @return string[] an array of all uids |
|
359 | - */ |
|
360 | - public function getUsers($search = '', $limit = null, $offset = null) { |
|
361 | - $users = $this->getDisplayNames($search, $limit, $offset); |
|
362 | - $userIds = array_map(function ($uid) { |
|
363 | - return (string)$uid; |
|
364 | - }, array_keys($users)); |
|
365 | - sort($userIds, SORT_STRING | SORT_FLAG_CASE); |
|
366 | - return $userIds; |
|
367 | - } |
|
368 | - |
|
369 | - /** |
|
370 | - * check if a user exists |
|
371 | - * |
|
372 | - * @param string $uid the username |
|
373 | - * @return boolean |
|
374 | - */ |
|
375 | - public function userExists($uid) { |
|
376 | - $this->loadUser($uid); |
|
377 | - return $this->cache[$uid] !== false; |
|
378 | - } |
|
379 | - |
|
380 | - /** |
|
381 | - * get the user's home directory |
|
382 | - * |
|
383 | - * @param string $uid the username |
|
384 | - * @return string|false |
|
385 | - */ |
|
386 | - public function getHome(string $uid) { |
|
387 | - if ($this->userExists($uid)) { |
|
388 | - return \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $uid; |
|
389 | - } |
|
390 | - |
|
391 | - return false; |
|
392 | - } |
|
393 | - |
|
394 | - /** |
|
395 | - * @return bool |
|
396 | - */ |
|
397 | - public function hasUserListings() { |
|
398 | - return true; |
|
399 | - } |
|
400 | - |
|
401 | - /** |
|
402 | - * counts the users in the database |
|
403 | - * |
|
404 | - * @return int|bool |
|
405 | - */ |
|
406 | - public function countUsers() { |
|
407 | - $this->fixDI(); |
|
408 | - |
|
409 | - $query = \OC_DB::prepare('SELECT COUNT(*) FROM `*PREFIX*users`'); |
|
410 | - $result = $query->execute(); |
|
411 | - if ($result === false) { |
|
412 | - Util::writeLog('core', \OC_DB::getErrorMessage(), ILogger::ERROR); |
|
413 | - return false; |
|
414 | - } |
|
415 | - return $result->fetchOne(); |
|
416 | - } |
|
417 | - |
|
418 | - /** |
|
419 | - * returns the username for the given login name in the correct casing |
|
420 | - * |
|
421 | - * @param string $loginName |
|
422 | - * @return string|false |
|
423 | - */ |
|
424 | - public function loginName2UserName($loginName) { |
|
425 | - if ($this->userExists($loginName)) { |
|
426 | - return $this->cache[$loginName]['uid']; |
|
427 | - } |
|
428 | - |
|
429 | - return false; |
|
430 | - } |
|
431 | - |
|
432 | - /** |
|
433 | - * Backend name to be shown in user management |
|
434 | - * |
|
435 | - * @return string the name of the backend to be shown |
|
436 | - */ |
|
437 | - public function getBackendName() { |
|
438 | - return 'Database'; |
|
439 | - } |
|
440 | - |
|
441 | - public static function preLoginNameUsedAsUserName($param) { |
|
442 | - if (!isset($param['uid'])) { |
|
443 | - throw new \Exception('key uid is expected to be set in $param'); |
|
444 | - } |
|
445 | - |
|
446 | - $backends = \OC::$server->getUserManager()->getBackends(); |
|
447 | - foreach ($backends as $backend) { |
|
448 | - if ($backend instanceof Database) { |
|
449 | - /** @var \OC\User\Database $backend */ |
|
450 | - $uid = $backend->loginName2UserName($param['uid']); |
|
451 | - if ($uid !== false) { |
|
452 | - $param['uid'] = $uid; |
|
453 | - return; |
|
454 | - } |
|
455 | - } |
|
456 | - } |
|
457 | - |
|
458 | - } |
|
79 | + implements ICreateUserBackend, |
|
80 | + ISetPasswordBackend, |
|
81 | + ISetDisplayNameBackend, |
|
82 | + IGetDisplayNameBackend, |
|
83 | + ICheckPasswordBackend, |
|
84 | + IGetHomeBackend, |
|
85 | + ICountUsersBackend { |
|
86 | + /** @var CappedMemoryCache */ |
|
87 | + private $cache; |
|
88 | + |
|
89 | + /** @var EventDispatcher */ |
|
90 | + private $eventDispatcher; |
|
91 | + |
|
92 | + /** @var IDBConnection */ |
|
93 | + private $dbConn; |
|
94 | + |
|
95 | + /** |
|
96 | + * \OC\User\Database constructor. |
|
97 | + * |
|
98 | + * @param EventDispatcher $eventDispatcher |
|
99 | + */ |
|
100 | + public function __construct($eventDispatcher = null) { |
|
101 | + $this->cache = new CappedMemoryCache(); |
|
102 | + $this->eventDispatcher = $eventDispatcher ? $eventDispatcher : \OC::$server->getEventDispatcher(); |
|
103 | + } |
|
104 | + |
|
105 | + /** |
|
106 | + * FIXME: This function should not be required! |
|
107 | + */ |
|
108 | + private function fixDI() { |
|
109 | + if ($this->dbConn === null) { |
|
110 | + $this->dbConn = \OC::$server->getDatabaseConnection(); |
|
111 | + } |
|
112 | + } |
|
113 | + |
|
114 | + /** |
|
115 | + * Create a new user |
|
116 | + * |
|
117 | + * @param string $uid The username of the user to create |
|
118 | + * @param string $password The password of the new user |
|
119 | + * @return bool |
|
120 | + * |
|
121 | + * Creates a new user. Basic checking of username is done in OC_User |
|
122 | + * itself, not in its subclasses. |
|
123 | + */ |
|
124 | + public function createUser(string $uid, string $password): bool { |
|
125 | + $this->fixDI(); |
|
126 | + |
|
127 | + if (!$this->userExists($uid)) { |
|
128 | + $event = new GenericEvent($password); |
|
129 | + $this->eventDispatcher->dispatch('OCP\PasswordPolicy::validate', $event); |
|
130 | + |
|
131 | + $qb = $this->dbConn->getQueryBuilder(); |
|
132 | + $qb->insert('users') |
|
133 | + ->values([ |
|
134 | + 'uid' => $qb->createNamedParameter($uid), |
|
135 | + 'password' => $qb->createNamedParameter(\OC::$server->getHasher()->hash($password)), |
|
136 | + 'uid_lower' => $qb->createNamedParameter(mb_strtolower($uid)), |
|
137 | + ]); |
|
138 | + |
|
139 | + $result = $qb->execute(); |
|
140 | + |
|
141 | + // Clear cache |
|
142 | + unset($this->cache[$uid]); |
|
143 | + |
|
144 | + return $result ? true : false; |
|
145 | + } |
|
146 | + |
|
147 | + return false; |
|
148 | + } |
|
149 | + |
|
150 | + /** |
|
151 | + * delete a user |
|
152 | + * |
|
153 | + * @param string $uid The username of the user to delete |
|
154 | + * @return bool |
|
155 | + * |
|
156 | + * Deletes a user |
|
157 | + */ |
|
158 | + public function deleteUser($uid) { |
|
159 | + $this->fixDI(); |
|
160 | + |
|
161 | + // Delete user-group-relation |
|
162 | + $query = \OC_DB::prepare('DELETE FROM `*PREFIX*users` WHERE `uid` = ?'); |
|
163 | + $result = $query->execute([$uid]); |
|
164 | + |
|
165 | + if (isset($this->cache[$uid])) { |
|
166 | + unset($this->cache[$uid]); |
|
167 | + } |
|
168 | + |
|
169 | + return $result ? true : false; |
|
170 | + } |
|
171 | + |
|
172 | + /** |
|
173 | + * Set password |
|
174 | + * |
|
175 | + * @param string $uid The username |
|
176 | + * @param string $password The new password |
|
177 | + * @return bool |
|
178 | + * |
|
179 | + * Change the password of a user |
|
180 | + */ |
|
181 | + public function setPassword(string $uid, string $password): bool { |
|
182 | + $this->fixDI(); |
|
183 | + |
|
184 | + if ($this->userExists($uid)) { |
|
185 | + $event = new GenericEvent($password); |
|
186 | + $this->eventDispatcher->dispatch('OCP\PasswordPolicy::validate', $event); |
|
187 | + $query = \OC_DB::prepare('UPDATE `*PREFIX*users` SET `password` = ? WHERE `uid` = ?'); |
|
188 | + $result = $query->execute([\OC::$server->getHasher()->hash($password), $uid]); |
|
189 | + |
|
190 | + return $result ? true : false; |
|
191 | + } |
|
192 | + |
|
193 | + return false; |
|
194 | + } |
|
195 | + |
|
196 | + /** |
|
197 | + * Set display name |
|
198 | + * |
|
199 | + * @param string $uid The username |
|
200 | + * @param string $displayName The new display name |
|
201 | + * @return bool |
|
202 | + * |
|
203 | + * Change the display name of a user |
|
204 | + */ |
|
205 | + public function setDisplayName(string $uid, string $displayName): bool { |
|
206 | + $this->fixDI(); |
|
207 | + |
|
208 | + if ($this->userExists($uid)) { |
|
209 | + $query = \OC_DB::prepare('UPDATE `*PREFIX*users` SET `displayname` = ? WHERE LOWER(`uid`) = LOWER(?)'); |
|
210 | + $query->execute([$displayName, $uid]); |
|
211 | + $this->cache[$uid]['displayname'] = $displayName; |
|
212 | + |
|
213 | + return true; |
|
214 | + } |
|
215 | + |
|
216 | + return false; |
|
217 | + } |
|
218 | + |
|
219 | + /** |
|
220 | + * get display name of the user |
|
221 | + * |
|
222 | + * @param string $uid user ID of the user |
|
223 | + * @return string display name |
|
224 | + */ |
|
225 | + public function getDisplayName($uid): string { |
|
226 | + $uid = (string)$uid; |
|
227 | + $this->loadUser($uid); |
|
228 | + return empty($this->cache[$uid]['displayname']) ? $uid : $this->cache[$uid]['displayname']; |
|
229 | + } |
|
230 | + |
|
231 | + /** |
|
232 | + * Get a list of all display names and user ids. |
|
233 | + * |
|
234 | + * @param string $search |
|
235 | + * @param string|null $limit |
|
236 | + * @param string|null $offset |
|
237 | + * @return array an array of all displayNames (value) and the corresponding uids (key) |
|
238 | + */ |
|
239 | + public function getDisplayNames($search = '', $limit = null, $offset = null) { |
|
240 | + $this->fixDI(); |
|
241 | + |
|
242 | + $query = $this->dbConn->getQueryBuilder(); |
|
243 | + |
|
244 | + $query->select('uid', 'displayname') |
|
245 | + ->from('users', 'u') |
|
246 | + ->leftJoin('u', 'preferences', 'p', $query->expr()->andX( |
|
247 | + $query->expr()->eq('userid', 'uid'), |
|
248 | + $query->expr()->eq('appid', $query->expr()->literal('settings')), |
|
249 | + $query->expr()->eq('configkey', $query->expr()->literal('email'))) |
|
250 | + ) |
|
251 | + // sqlite doesn't like re-using a single named parameter here |
|
252 | + ->where($query->expr()->iLike('uid', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%'))) |
|
253 | + ->orWhere($query->expr()->iLike('displayname', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%'))) |
|
254 | + ->orWhere($query->expr()->iLike('configvalue', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%'))) |
|
255 | + ->orderBy($query->func()->lower('displayname'), 'ASC') |
|
256 | + ->orderBy($query->func()->lower('uid'), 'ASC') |
|
257 | + ->setMaxResults($limit) |
|
258 | + ->setFirstResult($offset); |
|
259 | + |
|
260 | + $result = $query->execute(); |
|
261 | + $displayNames = []; |
|
262 | + while ($row = $result->fetch()) { |
|
263 | + $displayNames[(string)$row['uid']] = (string)$row['displayname']; |
|
264 | + } |
|
265 | + |
|
266 | + return $displayNames; |
|
267 | + } |
|
268 | + |
|
269 | + /** |
|
270 | + * Check if the password is correct |
|
271 | + * |
|
272 | + * @param string $uid The username |
|
273 | + * @param string $password The password |
|
274 | + * @return string |
|
275 | + * |
|
276 | + * Check if the password is correct without logging in the user |
|
277 | + * returns the user id or false |
|
278 | + */ |
|
279 | + public function checkPassword(string $uid, string $password) { |
|
280 | + $this->fixDI(); |
|
281 | + |
|
282 | + $qb = $this->dbConn->getQueryBuilder(); |
|
283 | + $qb->select('uid', 'password') |
|
284 | + ->from('users') |
|
285 | + ->where( |
|
286 | + $qb->expr()->eq( |
|
287 | + 'uid_lower', $qb->createNamedParameter(mb_strtolower($uid)) |
|
288 | + ) |
|
289 | + ); |
|
290 | + $result = $qb->execute(); |
|
291 | + $row = $result->fetch(); |
|
292 | + $result->closeCursor(); |
|
293 | + |
|
294 | + if ($row) { |
|
295 | + $storedHash = $row['password']; |
|
296 | + $newHash = ''; |
|
297 | + if (\OC::$server->getHasher()->verify($password, $storedHash, $newHash)) { |
|
298 | + if (!empty($newHash)) { |
|
299 | + $this->setPassword($uid, $password); |
|
300 | + } |
|
301 | + return (string)$row['uid']; |
|
302 | + } |
|
303 | + |
|
304 | + } |
|
305 | + |
|
306 | + return false; |
|
307 | + } |
|
308 | + |
|
309 | + /** |
|
310 | + * Load an user in the cache |
|
311 | + * |
|
312 | + * @param string $uid the username |
|
313 | + * @return boolean true if user was found, false otherwise |
|
314 | + */ |
|
315 | + private function loadUser($uid) { |
|
316 | + $this->fixDI(); |
|
317 | + |
|
318 | + $uid = (string)$uid; |
|
319 | + if (!isset($this->cache[$uid])) { |
|
320 | + //guests $uid could be NULL or '' |
|
321 | + if ($uid === '') { |
|
322 | + $this->cache[$uid] = false; |
|
323 | + return true; |
|
324 | + } |
|
325 | + |
|
326 | + $qb = $this->dbConn->getQueryBuilder(); |
|
327 | + $qb->select('uid', 'displayname') |
|
328 | + ->from('users') |
|
329 | + ->where( |
|
330 | + $qb->expr()->eq( |
|
331 | + 'uid_lower', $qb->createNamedParameter(mb_strtolower($uid)) |
|
332 | + ) |
|
333 | + ); |
|
334 | + $result = $qb->execute(); |
|
335 | + $row = $result->fetch(); |
|
336 | + $result->closeCursor(); |
|
337 | + |
|
338 | + $this->cache[$uid] = false; |
|
339 | + |
|
340 | + // "uid" is primary key, so there can only be a single result |
|
341 | + if ($row !== false) { |
|
342 | + $this->cache[$uid]['uid'] = (string)$row['uid']; |
|
343 | + $this->cache[$uid]['displayname'] = (string)$row['displayname']; |
|
344 | + } else { |
|
345 | + return false; |
|
346 | + } |
|
347 | + } |
|
348 | + |
|
349 | + return true; |
|
350 | + } |
|
351 | + |
|
352 | + /** |
|
353 | + * Get a list of all users |
|
354 | + * |
|
355 | + * @param string $search |
|
356 | + * @param null|int $limit |
|
357 | + * @param null|int $offset |
|
358 | + * @return string[] an array of all uids |
|
359 | + */ |
|
360 | + public function getUsers($search = '', $limit = null, $offset = null) { |
|
361 | + $users = $this->getDisplayNames($search, $limit, $offset); |
|
362 | + $userIds = array_map(function ($uid) { |
|
363 | + return (string)$uid; |
|
364 | + }, array_keys($users)); |
|
365 | + sort($userIds, SORT_STRING | SORT_FLAG_CASE); |
|
366 | + return $userIds; |
|
367 | + } |
|
368 | + |
|
369 | + /** |
|
370 | + * check if a user exists |
|
371 | + * |
|
372 | + * @param string $uid the username |
|
373 | + * @return boolean |
|
374 | + */ |
|
375 | + public function userExists($uid) { |
|
376 | + $this->loadUser($uid); |
|
377 | + return $this->cache[$uid] !== false; |
|
378 | + } |
|
379 | + |
|
380 | + /** |
|
381 | + * get the user's home directory |
|
382 | + * |
|
383 | + * @param string $uid the username |
|
384 | + * @return string|false |
|
385 | + */ |
|
386 | + public function getHome(string $uid) { |
|
387 | + if ($this->userExists($uid)) { |
|
388 | + return \OC::$server->getConfig()->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $uid; |
|
389 | + } |
|
390 | + |
|
391 | + return false; |
|
392 | + } |
|
393 | + |
|
394 | + /** |
|
395 | + * @return bool |
|
396 | + */ |
|
397 | + public function hasUserListings() { |
|
398 | + return true; |
|
399 | + } |
|
400 | + |
|
401 | + /** |
|
402 | + * counts the users in the database |
|
403 | + * |
|
404 | + * @return int|bool |
|
405 | + */ |
|
406 | + public function countUsers() { |
|
407 | + $this->fixDI(); |
|
408 | + |
|
409 | + $query = \OC_DB::prepare('SELECT COUNT(*) FROM `*PREFIX*users`'); |
|
410 | + $result = $query->execute(); |
|
411 | + if ($result === false) { |
|
412 | + Util::writeLog('core', \OC_DB::getErrorMessage(), ILogger::ERROR); |
|
413 | + return false; |
|
414 | + } |
|
415 | + return $result->fetchOne(); |
|
416 | + } |
|
417 | + |
|
418 | + /** |
|
419 | + * returns the username for the given login name in the correct casing |
|
420 | + * |
|
421 | + * @param string $loginName |
|
422 | + * @return string|false |
|
423 | + */ |
|
424 | + public function loginName2UserName($loginName) { |
|
425 | + if ($this->userExists($loginName)) { |
|
426 | + return $this->cache[$loginName]['uid']; |
|
427 | + } |
|
428 | + |
|
429 | + return false; |
|
430 | + } |
|
431 | + |
|
432 | + /** |
|
433 | + * Backend name to be shown in user management |
|
434 | + * |
|
435 | + * @return string the name of the backend to be shown |
|
436 | + */ |
|
437 | + public function getBackendName() { |
|
438 | + return 'Database'; |
|
439 | + } |
|
440 | + |
|
441 | + public static function preLoginNameUsedAsUserName($param) { |
|
442 | + if (!isset($param['uid'])) { |
|
443 | + throw new \Exception('key uid is expected to be set in $param'); |
|
444 | + } |
|
445 | + |
|
446 | + $backends = \OC::$server->getUserManager()->getBackends(); |
|
447 | + foreach ($backends as $backend) { |
|
448 | + if ($backend instanceof Database) { |
|
449 | + /** @var \OC\User\Database $backend */ |
|
450 | + $uid = $backend->loginName2UserName($param['uid']); |
|
451 | + if ($uid !== false) { |
|
452 | + $param['uid'] = $uid; |
|
453 | + return; |
|
454 | + } |
|
455 | + } |
|
456 | + } |
|
457 | + |
|
458 | + } |
|
459 | 459 | } |
@@ -52,552 +52,552 @@ |
||
52 | 52 | * This class provides the functionality needed to install, update and remove apps |
53 | 53 | */ |
54 | 54 | class Installer { |
55 | - /** @var AppFetcher */ |
|
56 | - private $appFetcher; |
|
57 | - /** @var IClientService */ |
|
58 | - private $clientService; |
|
59 | - /** @var ITempManager */ |
|
60 | - private $tempManager; |
|
61 | - /** @var ILogger */ |
|
62 | - private $logger; |
|
63 | - /** @var IConfig */ |
|
64 | - private $config; |
|
65 | - /** @var array - for caching the result of app fetcher */ |
|
66 | - private $apps = null; |
|
67 | - /** @var bool|null - for caching the result of the ready status */ |
|
68 | - private $isInstanceReadyForUpdates = null; |
|
69 | - |
|
70 | - /** |
|
71 | - * @param AppFetcher $appFetcher |
|
72 | - * @param IClientService $clientService |
|
73 | - * @param ITempManager $tempManager |
|
74 | - * @param ILogger $logger |
|
75 | - * @param IConfig $config |
|
76 | - */ |
|
77 | - public function __construct(AppFetcher $appFetcher, |
|
78 | - IClientService $clientService, |
|
79 | - ITempManager $tempManager, |
|
80 | - ILogger $logger, |
|
81 | - IConfig $config) { |
|
82 | - $this->appFetcher = $appFetcher; |
|
83 | - $this->clientService = $clientService; |
|
84 | - $this->tempManager = $tempManager; |
|
85 | - $this->logger = $logger; |
|
86 | - $this->config = $config; |
|
87 | - } |
|
88 | - |
|
89 | - /** |
|
90 | - * Installs an app that is located in one of the app folders already |
|
91 | - * |
|
92 | - * @param string $appId App to install |
|
93 | - * @throws \Exception |
|
94 | - * @return string app ID |
|
95 | - */ |
|
96 | - public function installApp($appId) { |
|
97 | - $app = \OC_App::findAppInDirectories($appId); |
|
98 | - if($app === false) { |
|
99 | - throw new \Exception('App not found in any app directory'); |
|
100 | - } |
|
101 | - |
|
102 | - $basedir = $app['path'].'/'.$appId; |
|
103 | - $info = OC_App::getAppInfo($basedir.'/appinfo/info.xml', true); |
|
104 | - |
|
105 | - $l = \OC::$server->getL10N('core'); |
|
106 | - |
|
107 | - if(!is_array($info)) { |
|
108 | - throw new \Exception( |
|
109 | - $l->t('App "%s" cannot be installed because appinfo file cannot be read.', |
|
110 | - [$appId] |
|
111 | - ) |
|
112 | - ); |
|
113 | - } |
|
114 | - |
|
115 | - $version = implode('.', \OCP\Util::getVersion()); |
|
116 | - if (!\OC_App::isAppCompatible($version, $info)) { |
|
117 | - throw new \Exception( |
|
118 | - // TODO $l |
|
119 | - $l->t('App "%s" cannot be installed because it is not compatible with this version of the server.', |
|
120 | - [$info['name']] |
|
121 | - ) |
|
122 | - ); |
|
123 | - } |
|
124 | - |
|
125 | - // check for required dependencies |
|
126 | - \OC_App::checkAppDependencies($this->config, $l, $info); |
|
127 | - \OC_App::registerAutoloading($appId, $basedir); |
|
128 | - |
|
129 | - //install the database |
|
130 | - if(is_file($basedir.'/appinfo/database.xml')) { |
|
131 | - if (\OC::$server->getConfig()->getAppValue($info['id'], 'installed_version') === null) { |
|
132 | - OC_DB::createDbFromStructure($basedir.'/appinfo/database.xml'); |
|
133 | - } else { |
|
134 | - OC_DB::updateDbFromStructure($basedir.'/appinfo/database.xml'); |
|
135 | - } |
|
136 | - } else { |
|
137 | - $ms = new \OC\DB\MigrationService($info['id'], \OC::$server->getDatabaseConnection()); |
|
138 | - $ms->migrate(); |
|
139 | - } |
|
140 | - |
|
141 | - \OC_App::setupBackgroundJobs($info['background-jobs']); |
|
142 | - |
|
143 | - //run appinfo/install.php |
|
144 | - self::includeAppScript($basedir . '/appinfo/install.php'); |
|
145 | - |
|
146 | - $appData = OC_App::getAppInfo($appId); |
|
147 | - OC_App::executeRepairSteps($appId, $appData['repair-steps']['install']); |
|
148 | - |
|
149 | - //set the installed version |
|
150 | - \OC::$server->getConfig()->setAppValue($info['id'], 'installed_version', OC_App::getAppVersion($info['id'], false)); |
|
151 | - \OC::$server->getConfig()->setAppValue($info['id'], 'enabled', 'no'); |
|
152 | - |
|
153 | - //set remote/public handlers |
|
154 | - foreach($info['remote'] as $name=>$path) { |
|
155 | - \OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $info['id'].'/'.$path); |
|
156 | - } |
|
157 | - foreach($info['public'] as $name=>$path) { |
|
158 | - \OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $info['id'].'/'.$path); |
|
159 | - } |
|
160 | - |
|
161 | - OC_App::setAppTypes($info['id']); |
|
162 | - |
|
163 | - return $info['id']; |
|
164 | - } |
|
165 | - |
|
166 | - /** |
|
167 | - * Updates the specified app from the appstore |
|
168 | - * |
|
169 | - * @param string $appId |
|
170 | - * @return bool |
|
171 | - */ |
|
172 | - public function updateAppstoreApp($appId) { |
|
173 | - if($this->isUpdateAvailable($appId)) { |
|
174 | - try { |
|
175 | - $this->downloadApp($appId); |
|
176 | - } catch (\Exception $e) { |
|
177 | - $this->logger->logException($e, [ |
|
178 | - 'level' => ILogger::ERROR, |
|
179 | - 'app' => 'core', |
|
180 | - ]); |
|
181 | - return false; |
|
182 | - } |
|
183 | - return OC_App::updateApp($appId); |
|
184 | - } |
|
185 | - |
|
186 | - return false; |
|
187 | - } |
|
188 | - |
|
189 | - /** |
|
190 | - * Downloads an app and puts it into the app directory |
|
191 | - * |
|
192 | - * @param string $appId |
|
193 | - * |
|
194 | - * @throws \Exception If the installation was not successful |
|
195 | - */ |
|
196 | - public function downloadApp($appId) { |
|
197 | - $appId = strtolower($appId); |
|
198 | - |
|
199 | - $apps = $this->appFetcher->get(); |
|
200 | - foreach($apps as $app) { |
|
201 | - if($app['id'] === $appId) { |
|
202 | - // Load the certificate |
|
203 | - $certificate = new X509(); |
|
204 | - $certificate->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt')); |
|
205 | - $loadedCertificate = $certificate->loadX509($app['certificate']); |
|
206 | - |
|
207 | - // Verify if the certificate has been revoked |
|
208 | - $crl = new X509(); |
|
209 | - $crl->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt')); |
|
210 | - $crl->loadCRL(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crl')); |
|
211 | - if($crl->validateSignature() !== true) { |
|
212 | - throw new \Exception('Could not validate CRL signature'); |
|
213 | - } |
|
214 | - $csn = $loadedCertificate['tbsCertificate']['serialNumber']->toString(); |
|
215 | - $revoked = $crl->getRevoked($csn); |
|
216 | - if ($revoked !== false) { |
|
217 | - throw new \Exception( |
|
218 | - sprintf( |
|
219 | - 'Certificate "%s" has been revoked', |
|
220 | - $csn |
|
221 | - ) |
|
222 | - ); |
|
223 | - } |
|
224 | - |
|
225 | - // Verify if the certificate has been issued by the Nextcloud Code Authority CA |
|
226 | - if($certificate->validateSignature() !== true) { |
|
227 | - throw new \Exception( |
|
228 | - sprintf( |
|
229 | - 'App with id %s has a certificate not issued by a trusted Code Signing Authority', |
|
230 | - $appId |
|
231 | - ) |
|
232 | - ); |
|
233 | - } |
|
234 | - |
|
235 | - // Verify if the certificate is issued for the requested app id |
|
236 | - $certInfo = openssl_x509_parse($app['certificate']); |
|
237 | - if(!isset($certInfo['subject']['CN'])) { |
|
238 | - throw new \Exception( |
|
239 | - sprintf( |
|
240 | - 'App with id %s has a cert with no CN', |
|
241 | - $appId |
|
242 | - ) |
|
243 | - ); |
|
244 | - } |
|
245 | - if($certInfo['subject']['CN'] !== $appId) { |
|
246 | - throw new \Exception( |
|
247 | - sprintf( |
|
248 | - 'App with id %s has a cert issued to %s', |
|
249 | - $appId, |
|
250 | - $certInfo['subject']['CN'] |
|
251 | - ) |
|
252 | - ); |
|
253 | - } |
|
254 | - |
|
255 | - // Download the release |
|
256 | - $tempFile = $this->tempManager->getTemporaryFile('.tar.gz'); |
|
257 | - $client = $this->clientService->newClient(); |
|
258 | - $client->get($app['releases'][0]['download'], ['save_to' => $tempFile]); |
|
259 | - |
|
260 | - // Check if the signature actually matches the downloaded content |
|
261 | - $certificate = openssl_get_publickey($app['certificate']); |
|
262 | - $verified = (bool)openssl_verify(file_get_contents($tempFile), base64_decode($app['releases'][0]['signature']), $certificate, OPENSSL_ALGO_SHA512); |
|
263 | - openssl_free_key($certificate); |
|
264 | - |
|
265 | - if($verified === true) { |
|
266 | - // Seems to match, let's proceed |
|
267 | - $extractDir = $this->tempManager->getTemporaryFolder(); |
|
268 | - $archive = new TAR($tempFile); |
|
269 | - |
|
270 | - if($archive) { |
|
271 | - if (!$archive->extract($extractDir)) { |
|
272 | - throw new \Exception( |
|
273 | - sprintf( |
|
274 | - 'Could not extract app %s', |
|
275 | - $appId |
|
276 | - ) |
|
277 | - ); |
|
278 | - } |
|
279 | - $allFiles = scandir($extractDir); |
|
280 | - $folders = array_diff($allFiles, ['.', '..']); |
|
281 | - $folders = array_values($folders); |
|
282 | - |
|
283 | - if(count($folders) > 1) { |
|
284 | - throw new \Exception( |
|
285 | - sprintf( |
|
286 | - 'Extracted app %s has more than 1 folder', |
|
287 | - $appId |
|
288 | - ) |
|
289 | - ); |
|
290 | - } |
|
291 | - |
|
292 | - // Check if appinfo/info.xml has the same app ID as well |
|
293 | - $loadEntities = libxml_disable_entity_loader(false); |
|
294 | - $xml = simplexml_load_file($extractDir . '/' . $folders[0] . '/appinfo/info.xml'); |
|
295 | - libxml_disable_entity_loader($loadEntities); |
|
296 | - if((string)$xml->id !== $appId) { |
|
297 | - throw new \Exception( |
|
298 | - sprintf( |
|
299 | - 'App for id %s has a wrong app ID in info.xml: %s', |
|
300 | - $appId, |
|
301 | - (string)$xml->id |
|
302 | - ) |
|
303 | - ); |
|
304 | - } |
|
305 | - |
|
306 | - // Check if the version is lower than before |
|
307 | - $currentVersion = OC_App::getAppVersion($appId); |
|
308 | - $newVersion = (string)$xml->version; |
|
309 | - if(version_compare($currentVersion, $newVersion) === 1) { |
|
310 | - throw new \Exception( |
|
311 | - sprintf( |
|
312 | - 'App for id %s has version %s and tried to update to lower version %s', |
|
313 | - $appId, |
|
314 | - $currentVersion, |
|
315 | - $newVersion |
|
316 | - ) |
|
317 | - ); |
|
318 | - } |
|
319 | - |
|
320 | - $baseDir = OC_App::getInstallPath() . '/' . $appId; |
|
321 | - // Remove old app with the ID if existent |
|
322 | - OC_Helper::rmdirr($baseDir); |
|
323 | - // Move to app folder |
|
324 | - if(@mkdir($baseDir)) { |
|
325 | - $extractDir .= '/' . $folders[0]; |
|
326 | - OC_Helper::copyr($extractDir, $baseDir); |
|
327 | - } |
|
328 | - OC_Helper::copyr($extractDir, $baseDir); |
|
329 | - OC_Helper::rmdirr($extractDir); |
|
330 | - return; |
|
331 | - } else { |
|
332 | - throw new \Exception( |
|
333 | - sprintf( |
|
334 | - 'Could not extract app with ID %s to %s', |
|
335 | - $appId, |
|
336 | - $extractDir |
|
337 | - ) |
|
338 | - ); |
|
339 | - } |
|
340 | - } else { |
|
341 | - // Signature does not match |
|
342 | - throw new \Exception( |
|
343 | - sprintf( |
|
344 | - 'App with id %s has invalid signature', |
|
345 | - $appId |
|
346 | - ) |
|
347 | - ); |
|
348 | - } |
|
349 | - } |
|
350 | - } |
|
351 | - |
|
352 | - throw new \Exception( |
|
353 | - sprintf( |
|
354 | - 'Could not download app %s', |
|
355 | - $appId |
|
356 | - ) |
|
357 | - ); |
|
358 | - } |
|
359 | - |
|
360 | - /** |
|
361 | - * Check if an update for the app is available |
|
362 | - * |
|
363 | - * @param string $appId |
|
364 | - * @return string|false false or the version number of the update |
|
365 | - */ |
|
366 | - public function isUpdateAvailable($appId) { |
|
367 | - if ($this->isInstanceReadyForUpdates === null) { |
|
368 | - $installPath = OC_App::getInstallPath(); |
|
369 | - if ($installPath === false || $installPath === null) { |
|
370 | - $this->isInstanceReadyForUpdates = false; |
|
371 | - } else { |
|
372 | - $this->isInstanceReadyForUpdates = true; |
|
373 | - } |
|
374 | - } |
|
375 | - |
|
376 | - if ($this->isInstanceReadyForUpdates === false) { |
|
377 | - return false; |
|
378 | - } |
|
379 | - |
|
380 | - if ($this->isInstalledFromGit($appId) === true) { |
|
381 | - return false; |
|
382 | - } |
|
383 | - |
|
384 | - if ($this->apps === null) { |
|
385 | - $this->apps = $this->appFetcher->get(); |
|
386 | - } |
|
387 | - |
|
388 | - foreach($this->apps as $app) { |
|
389 | - if($app['id'] === $appId) { |
|
390 | - $currentVersion = OC_App::getAppVersion($appId); |
|
391 | - $newestVersion = $app['releases'][0]['version']; |
|
392 | - if (version_compare($newestVersion, $currentVersion, '>')) { |
|
393 | - return $newestVersion; |
|
394 | - } else { |
|
395 | - return false; |
|
396 | - } |
|
397 | - } |
|
398 | - } |
|
399 | - |
|
400 | - return false; |
|
401 | - } |
|
402 | - |
|
403 | - /** |
|
404 | - * Check if app has been installed from git |
|
405 | - * @param string $name name of the application to remove |
|
406 | - * @return boolean |
|
407 | - * |
|
408 | - * The function will check if the path contains a .git folder |
|
409 | - */ |
|
410 | - private function isInstalledFromGit($appId) { |
|
411 | - $app = \OC_App::findAppInDirectories($appId); |
|
412 | - if($app === false) { |
|
413 | - return false; |
|
414 | - } |
|
415 | - $basedir = $app['path'].'/'.$appId; |
|
416 | - return file_exists($basedir.'/.git/'); |
|
417 | - } |
|
418 | - |
|
419 | - /** |
|
420 | - * Check if app is already downloaded |
|
421 | - * @param string $name name of the application to remove |
|
422 | - * @return boolean |
|
423 | - * |
|
424 | - * The function will check if the app is already downloaded in the apps repository |
|
425 | - */ |
|
426 | - public function isDownloaded($name) { |
|
427 | - foreach(\OC::$APPSROOTS as $dir) { |
|
428 | - $dirToTest = $dir['path']; |
|
429 | - $dirToTest .= '/'; |
|
430 | - $dirToTest .= $name; |
|
431 | - $dirToTest .= '/'; |
|
432 | - |
|
433 | - if (is_dir($dirToTest)) { |
|
434 | - return true; |
|
435 | - } |
|
436 | - } |
|
437 | - |
|
438 | - return false; |
|
439 | - } |
|
440 | - |
|
441 | - /** |
|
442 | - * Removes an app |
|
443 | - * @param string $appId ID of the application to remove |
|
444 | - * @return boolean |
|
445 | - * |
|
446 | - * |
|
447 | - * This function works as follows |
|
448 | - * -# call uninstall repair steps |
|
449 | - * -# removing the files |
|
450 | - * |
|
451 | - * The function will not delete preferences, tables and the configuration, |
|
452 | - * this has to be done by the function oc_app_uninstall(). |
|
453 | - */ |
|
454 | - public function removeApp($appId) { |
|
455 | - if($this->isDownloaded( $appId )) { |
|
456 | - if (\OC::$server->getAppManager()->isShipped($appId)) { |
|
457 | - return false; |
|
458 | - } |
|
459 | - $appDir = OC_App::getInstallPath() . '/' . $appId; |
|
460 | - OC_Helper::rmdirr($appDir); |
|
461 | - return true; |
|
462 | - }else{ |
|
463 | - \OCP\Util::writeLog('core', 'can\'t remove app '.$appId.'. It is not installed.', ILogger::ERROR); |
|
464 | - |
|
465 | - return false; |
|
466 | - } |
|
467 | - |
|
468 | - } |
|
469 | - |
|
470 | - /** |
|
471 | - * Installs the app within the bundle and marks the bundle as installed |
|
472 | - * |
|
473 | - * @param Bundle $bundle |
|
474 | - * @throws \Exception If app could not get installed |
|
475 | - */ |
|
476 | - public function installAppBundle(Bundle $bundle) { |
|
477 | - $appIds = $bundle->getAppIdentifiers(); |
|
478 | - foreach($appIds as $appId) { |
|
479 | - if(!$this->isDownloaded($appId)) { |
|
480 | - $this->downloadApp($appId); |
|
481 | - } |
|
482 | - $this->installApp($appId); |
|
483 | - $app = new OC_App(); |
|
484 | - $app->enable($appId); |
|
485 | - } |
|
486 | - $bundles = json_decode($this->config->getAppValue('core', 'installed.bundles', json_encode([])), true); |
|
487 | - $bundles[] = $bundle->getIdentifier(); |
|
488 | - $this->config->setAppValue('core', 'installed.bundles', json_encode($bundles)); |
|
489 | - } |
|
490 | - |
|
491 | - /** |
|
492 | - * Installs shipped apps |
|
493 | - * |
|
494 | - * This function installs all apps found in the 'apps' directory that should be enabled by default; |
|
495 | - * @param bool $softErrors When updating we ignore errors and simply log them, better to have a |
|
496 | - * working ownCloud at the end instead of an aborted update. |
|
497 | - * @return array Array of error messages (appid => Exception) |
|
498 | - */ |
|
499 | - public static function installShippedApps($softErrors = false) { |
|
500 | - $appManager = \OC::$server->getAppManager(); |
|
501 | - $config = \OC::$server->getConfig(); |
|
502 | - $errors = []; |
|
503 | - foreach(\OC::$APPSROOTS as $app_dir) { |
|
504 | - if($dir = opendir( $app_dir['path'] )) { |
|
505 | - while( false !== ( $filename = readdir( $dir ))) { |
|
506 | - if( $filename[0] !== '.' and is_dir($app_dir['path']."/$filename") ) { |
|
507 | - if( file_exists( $app_dir['path']."/$filename/appinfo/info.xml" )) { |
|
508 | - if($config->getAppValue($filename, "installed_version", null) === null) { |
|
509 | - $info=OC_App::getAppInfo($filename); |
|
510 | - $enabled = isset($info['default_enable']); |
|
511 | - if (($enabled || in_array($filename, $appManager->getAlwaysEnabledApps())) |
|
512 | - && $config->getAppValue($filename, 'enabled') !== 'no') { |
|
513 | - if ($softErrors) { |
|
514 | - try { |
|
515 | - Installer::installShippedApp($filename); |
|
516 | - } catch (HintException $e) { |
|
517 | - if ($e->getPrevious() instanceof TableExistsException) { |
|
518 | - $errors[$filename] = $e; |
|
519 | - continue; |
|
520 | - } |
|
521 | - throw $e; |
|
522 | - } |
|
523 | - } else { |
|
524 | - Installer::installShippedApp($filename); |
|
525 | - } |
|
526 | - $config->setAppValue($filename, 'enabled', 'yes'); |
|
527 | - } |
|
528 | - } |
|
529 | - } |
|
530 | - } |
|
531 | - } |
|
532 | - closedir( $dir ); |
|
533 | - } |
|
534 | - } |
|
535 | - |
|
536 | - return $errors; |
|
537 | - } |
|
538 | - |
|
539 | - /** |
|
540 | - * install an app already placed in the app folder |
|
541 | - * @param string $app id of the app to install |
|
542 | - * @return integer |
|
543 | - */ |
|
544 | - public static function installShippedApp($app) { |
|
545 | - //install the database |
|
546 | - $appPath = OC_App::getAppPath($app); |
|
547 | - \OC_App::registerAutoloading($app, $appPath); |
|
548 | - |
|
549 | - if(is_file("$appPath/appinfo/database.xml")) { |
|
550 | - try { |
|
551 | - OC_DB::createDbFromStructure("$appPath/appinfo/database.xml"); |
|
552 | - } catch (TableExistsException $e) { |
|
553 | - throw new HintException( |
|
554 | - 'Failed to enable app ' . $app, |
|
555 | - 'Please ask for help via one of our <a href="https://nextcloud.com/support/" target="_blank" rel="noreferrer noopener">support channels</a>.', |
|
556 | - 0, $e |
|
557 | - ); |
|
558 | - } |
|
559 | - } else { |
|
560 | - $ms = new \OC\DB\MigrationService($app, \OC::$server->getDatabaseConnection()); |
|
561 | - $ms->migrate(); |
|
562 | - } |
|
563 | - |
|
564 | - //run appinfo/install.php |
|
565 | - self::includeAppScript("$appPath/appinfo/install.php"); |
|
566 | - |
|
567 | - $info = OC_App::getAppInfo($app); |
|
568 | - if (is_null($info)) { |
|
569 | - return false; |
|
570 | - } |
|
571 | - \OC_App::setupBackgroundJobs($info['background-jobs']); |
|
572 | - |
|
573 | - OC_App::executeRepairSteps($app, $info['repair-steps']['install']); |
|
574 | - |
|
575 | - $config = \OC::$server->getConfig(); |
|
576 | - |
|
577 | - $config->setAppValue($app, 'installed_version', OC_App::getAppVersion($app)); |
|
578 | - if (array_key_exists('ocsid', $info)) { |
|
579 | - $config->setAppValue($app, 'ocsid', $info['ocsid']); |
|
580 | - } |
|
581 | - |
|
582 | - //set remote/public handlers |
|
583 | - foreach($info['remote'] as $name=>$path) { |
|
584 | - $config->setAppValue('core', 'remote_'.$name, $app.'/'.$path); |
|
585 | - } |
|
586 | - foreach($info['public'] as $name=>$path) { |
|
587 | - $config->setAppValue('core', 'public_'.$name, $app.'/'.$path); |
|
588 | - } |
|
589 | - |
|
590 | - OC_App::setAppTypes($info['id']); |
|
591 | - |
|
592 | - return $info['id']; |
|
593 | - } |
|
594 | - |
|
595 | - /** |
|
596 | - * @param string $script |
|
597 | - */ |
|
598 | - private static function includeAppScript($script) { |
|
599 | - if ( file_exists($script) ){ |
|
600 | - include $script; |
|
601 | - } |
|
602 | - } |
|
55 | + /** @var AppFetcher */ |
|
56 | + private $appFetcher; |
|
57 | + /** @var IClientService */ |
|
58 | + private $clientService; |
|
59 | + /** @var ITempManager */ |
|
60 | + private $tempManager; |
|
61 | + /** @var ILogger */ |
|
62 | + private $logger; |
|
63 | + /** @var IConfig */ |
|
64 | + private $config; |
|
65 | + /** @var array - for caching the result of app fetcher */ |
|
66 | + private $apps = null; |
|
67 | + /** @var bool|null - for caching the result of the ready status */ |
|
68 | + private $isInstanceReadyForUpdates = null; |
|
69 | + |
|
70 | + /** |
|
71 | + * @param AppFetcher $appFetcher |
|
72 | + * @param IClientService $clientService |
|
73 | + * @param ITempManager $tempManager |
|
74 | + * @param ILogger $logger |
|
75 | + * @param IConfig $config |
|
76 | + */ |
|
77 | + public function __construct(AppFetcher $appFetcher, |
|
78 | + IClientService $clientService, |
|
79 | + ITempManager $tempManager, |
|
80 | + ILogger $logger, |
|
81 | + IConfig $config) { |
|
82 | + $this->appFetcher = $appFetcher; |
|
83 | + $this->clientService = $clientService; |
|
84 | + $this->tempManager = $tempManager; |
|
85 | + $this->logger = $logger; |
|
86 | + $this->config = $config; |
|
87 | + } |
|
88 | + |
|
89 | + /** |
|
90 | + * Installs an app that is located in one of the app folders already |
|
91 | + * |
|
92 | + * @param string $appId App to install |
|
93 | + * @throws \Exception |
|
94 | + * @return string app ID |
|
95 | + */ |
|
96 | + public function installApp($appId) { |
|
97 | + $app = \OC_App::findAppInDirectories($appId); |
|
98 | + if($app === false) { |
|
99 | + throw new \Exception('App not found in any app directory'); |
|
100 | + } |
|
101 | + |
|
102 | + $basedir = $app['path'].'/'.$appId; |
|
103 | + $info = OC_App::getAppInfo($basedir.'/appinfo/info.xml', true); |
|
104 | + |
|
105 | + $l = \OC::$server->getL10N('core'); |
|
106 | + |
|
107 | + if(!is_array($info)) { |
|
108 | + throw new \Exception( |
|
109 | + $l->t('App "%s" cannot be installed because appinfo file cannot be read.', |
|
110 | + [$appId] |
|
111 | + ) |
|
112 | + ); |
|
113 | + } |
|
114 | + |
|
115 | + $version = implode('.', \OCP\Util::getVersion()); |
|
116 | + if (!\OC_App::isAppCompatible($version, $info)) { |
|
117 | + throw new \Exception( |
|
118 | + // TODO $l |
|
119 | + $l->t('App "%s" cannot be installed because it is not compatible with this version of the server.', |
|
120 | + [$info['name']] |
|
121 | + ) |
|
122 | + ); |
|
123 | + } |
|
124 | + |
|
125 | + // check for required dependencies |
|
126 | + \OC_App::checkAppDependencies($this->config, $l, $info); |
|
127 | + \OC_App::registerAutoloading($appId, $basedir); |
|
128 | + |
|
129 | + //install the database |
|
130 | + if(is_file($basedir.'/appinfo/database.xml')) { |
|
131 | + if (\OC::$server->getConfig()->getAppValue($info['id'], 'installed_version') === null) { |
|
132 | + OC_DB::createDbFromStructure($basedir.'/appinfo/database.xml'); |
|
133 | + } else { |
|
134 | + OC_DB::updateDbFromStructure($basedir.'/appinfo/database.xml'); |
|
135 | + } |
|
136 | + } else { |
|
137 | + $ms = new \OC\DB\MigrationService($info['id'], \OC::$server->getDatabaseConnection()); |
|
138 | + $ms->migrate(); |
|
139 | + } |
|
140 | + |
|
141 | + \OC_App::setupBackgroundJobs($info['background-jobs']); |
|
142 | + |
|
143 | + //run appinfo/install.php |
|
144 | + self::includeAppScript($basedir . '/appinfo/install.php'); |
|
145 | + |
|
146 | + $appData = OC_App::getAppInfo($appId); |
|
147 | + OC_App::executeRepairSteps($appId, $appData['repair-steps']['install']); |
|
148 | + |
|
149 | + //set the installed version |
|
150 | + \OC::$server->getConfig()->setAppValue($info['id'], 'installed_version', OC_App::getAppVersion($info['id'], false)); |
|
151 | + \OC::$server->getConfig()->setAppValue($info['id'], 'enabled', 'no'); |
|
152 | + |
|
153 | + //set remote/public handlers |
|
154 | + foreach($info['remote'] as $name=>$path) { |
|
155 | + \OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $info['id'].'/'.$path); |
|
156 | + } |
|
157 | + foreach($info['public'] as $name=>$path) { |
|
158 | + \OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $info['id'].'/'.$path); |
|
159 | + } |
|
160 | + |
|
161 | + OC_App::setAppTypes($info['id']); |
|
162 | + |
|
163 | + return $info['id']; |
|
164 | + } |
|
165 | + |
|
166 | + /** |
|
167 | + * Updates the specified app from the appstore |
|
168 | + * |
|
169 | + * @param string $appId |
|
170 | + * @return bool |
|
171 | + */ |
|
172 | + public function updateAppstoreApp($appId) { |
|
173 | + if($this->isUpdateAvailable($appId)) { |
|
174 | + try { |
|
175 | + $this->downloadApp($appId); |
|
176 | + } catch (\Exception $e) { |
|
177 | + $this->logger->logException($e, [ |
|
178 | + 'level' => ILogger::ERROR, |
|
179 | + 'app' => 'core', |
|
180 | + ]); |
|
181 | + return false; |
|
182 | + } |
|
183 | + return OC_App::updateApp($appId); |
|
184 | + } |
|
185 | + |
|
186 | + return false; |
|
187 | + } |
|
188 | + |
|
189 | + /** |
|
190 | + * Downloads an app and puts it into the app directory |
|
191 | + * |
|
192 | + * @param string $appId |
|
193 | + * |
|
194 | + * @throws \Exception If the installation was not successful |
|
195 | + */ |
|
196 | + public function downloadApp($appId) { |
|
197 | + $appId = strtolower($appId); |
|
198 | + |
|
199 | + $apps = $this->appFetcher->get(); |
|
200 | + foreach($apps as $app) { |
|
201 | + if($app['id'] === $appId) { |
|
202 | + // Load the certificate |
|
203 | + $certificate = new X509(); |
|
204 | + $certificate->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt')); |
|
205 | + $loadedCertificate = $certificate->loadX509($app['certificate']); |
|
206 | + |
|
207 | + // Verify if the certificate has been revoked |
|
208 | + $crl = new X509(); |
|
209 | + $crl->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt')); |
|
210 | + $crl->loadCRL(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crl')); |
|
211 | + if($crl->validateSignature() !== true) { |
|
212 | + throw new \Exception('Could not validate CRL signature'); |
|
213 | + } |
|
214 | + $csn = $loadedCertificate['tbsCertificate']['serialNumber']->toString(); |
|
215 | + $revoked = $crl->getRevoked($csn); |
|
216 | + if ($revoked !== false) { |
|
217 | + throw new \Exception( |
|
218 | + sprintf( |
|
219 | + 'Certificate "%s" has been revoked', |
|
220 | + $csn |
|
221 | + ) |
|
222 | + ); |
|
223 | + } |
|
224 | + |
|
225 | + // Verify if the certificate has been issued by the Nextcloud Code Authority CA |
|
226 | + if($certificate->validateSignature() !== true) { |
|
227 | + throw new \Exception( |
|
228 | + sprintf( |
|
229 | + 'App with id %s has a certificate not issued by a trusted Code Signing Authority', |
|
230 | + $appId |
|
231 | + ) |
|
232 | + ); |
|
233 | + } |
|
234 | + |
|
235 | + // Verify if the certificate is issued for the requested app id |
|
236 | + $certInfo = openssl_x509_parse($app['certificate']); |
|
237 | + if(!isset($certInfo['subject']['CN'])) { |
|
238 | + throw new \Exception( |
|
239 | + sprintf( |
|
240 | + 'App with id %s has a cert with no CN', |
|
241 | + $appId |
|
242 | + ) |
|
243 | + ); |
|
244 | + } |
|
245 | + if($certInfo['subject']['CN'] !== $appId) { |
|
246 | + throw new \Exception( |
|
247 | + sprintf( |
|
248 | + 'App with id %s has a cert issued to %s', |
|
249 | + $appId, |
|
250 | + $certInfo['subject']['CN'] |
|
251 | + ) |
|
252 | + ); |
|
253 | + } |
|
254 | + |
|
255 | + // Download the release |
|
256 | + $tempFile = $this->tempManager->getTemporaryFile('.tar.gz'); |
|
257 | + $client = $this->clientService->newClient(); |
|
258 | + $client->get($app['releases'][0]['download'], ['save_to' => $tempFile]); |
|
259 | + |
|
260 | + // Check if the signature actually matches the downloaded content |
|
261 | + $certificate = openssl_get_publickey($app['certificate']); |
|
262 | + $verified = (bool)openssl_verify(file_get_contents($tempFile), base64_decode($app['releases'][0]['signature']), $certificate, OPENSSL_ALGO_SHA512); |
|
263 | + openssl_free_key($certificate); |
|
264 | + |
|
265 | + if($verified === true) { |
|
266 | + // Seems to match, let's proceed |
|
267 | + $extractDir = $this->tempManager->getTemporaryFolder(); |
|
268 | + $archive = new TAR($tempFile); |
|
269 | + |
|
270 | + if($archive) { |
|
271 | + if (!$archive->extract($extractDir)) { |
|
272 | + throw new \Exception( |
|
273 | + sprintf( |
|
274 | + 'Could not extract app %s', |
|
275 | + $appId |
|
276 | + ) |
|
277 | + ); |
|
278 | + } |
|
279 | + $allFiles = scandir($extractDir); |
|
280 | + $folders = array_diff($allFiles, ['.', '..']); |
|
281 | + $folders = array_values($folders); |
|
282 | + |
|
283 | + if(count($folders) > 1) { |
|
284 | + throw new \Exception( |
|
285 | + sprintf( |
|
286 | + 'Extracted app %s has more than 1 folder', |
|
287 | + $appId |
|
288 | + ) |
|
289 | + ); |
|
290 | + } |
|
291 | + |
|
292 | + // Check if appinfo/info.xml has the same app ID as well |
|
293 | + $loadEntities = libxml_disable_entity_loader(false); |
|
294 | + $xml = simplexml_load_file($extractDir . '/' . $folders[0] . '/appinfo/info.xml'); |
|
295 | + libxml_disable_entity_loader($loadEntities); |
|
296 | + if((string)$xml->id !== $appId) { |
|
297 | + throw new \Exception( |
|
298 | + sprintf( |
|
299 | + 'App for id %s has a wrong app ID in info.xml: %s', |
|
300 | + $appId, |
|
301 | + (string)$xml->id |
|
302 | + ) |
|
303 | + ); |
|
304 | + } |
|
305 | + |
|
306 | + // Check if the version is lower than before |
|
307 | + $currentVersion = OC_App::getAppVersion($appId); |
|
308 | + $newVersion = (string)$xml->version; |
|
309 | + if(version_compare($currentVersion, $newVersion) === 1) { |
|
310 | + throw new \Exception( |
|
311 | + sprintf( |
|
312 | + 'App for id %s has version %s and tried to update to lower version %s', |
|
313 | + $appId, |
|
314 | + $currentVersion, |
|
315 | + $newVersion |
|
316 | + ) |
|
317 | + ); |
|
318 | + } |
|
319 | + |
|
320 | + $baseDir = OC_App::getInstallPath() . '/' . $appId; |
|
321 | + // Remove old app with the ID if existent |
|
322 | + OC_Helper::rmdirr($baseDir); |
|
323 | + // Move to app folder |
|
324 | + if(@mkdir($baseDir)) { |
|
325 | + $extractDir .= '/' . $folders[0]; |
|
326 | + OC_Helper::copyr($extractDir, $baseDir); |
|
327 | + } |
|
328 | + OC_Helper::copyr($extractDir, $baseDir); |
|
329 | + OC_Helper::rmdirr($extractDir); |
|
330 | + return; |
|
331 | + } else { |
|
332 | + throw new \Exception( |
|
333 | + sprintf( |
|
334 | + 'Could not extract app with ID %s to %s', |
|
335 | + $appId, |
|
336 | + $extractDir |
|
337 | + ) |
|
338 | + ); |
|
339 | + } |
|
340 | + } else { |
|
341 | + // Signature does not match |
|
342 | + throw new \Exception( |
|
343 | + sprintf( |
|
344 | + 'App with id %s has invalid signature', |
|
345 | + $appId |
|
346 | + ) |
|
347 | + ); |
|
348 | + } |
|
349 | + } |
|
350 | + } |
|
351 | + |
|
352 | + throw new \Exception( |
|
353 | + sprintf( |
|
354 | + 'Could not download app %s', |
|
355 | + $appId |
|
356 | + ) |
|
357 | + ); |
|
358 | + } |
|
359 | + |
|
360 | + /** |
|
361 | + * Check if an update for the app is available |
|
362 | + * |
|
363 | + * @param string $appId |
|
364 | + * @return string|false false or the version number of the update |
|
365 | + */ |
|
366 | + public function isUpdateAvailable($appId) { |
|
367 | + if ($this->isInstanceReadyForUpdates === null) { |
|
368 | + $installPath = OC_App::getInstallPath(); |
|
369 | + if ($installPath === false || $installPath === null) { |
|
370 | + $this->isInstanceReadyForUpdates = false; |
|
371 | + } else { |
|
372 | + $this->isInstanceReadyForUpdates = true; |
|
373 | + } |
|
374 | + } |
|
375 | + |
|
376 | + if ($this->isInstanceReadyForUpdates === false) { |
|
377 | + return false; |
|
378 | + } |
|
379 | + |
|
380 | + if ($this->isInstalledFromGit($appId) === true) { |
|
381 | + return false; |
|
382 | + } |
|
383 | + |
|
384 | + if ($this->apps === null) { |
|
385 | + $this->apps = $this->appFetcher->get(); |
|
386 | + } |
|
387 | + |
|
388 | + foreach($this->apps as $app) { |
|
389 | + if($app['id'] === $appId) { |
|
390 | + $currentVersion = OC_App::getAppVersion($appId); |
|
391 | + $newestVersion = $app['releases'][0]['version']; |
|
392 | + if (version_compare($newestVersion, $currentVersion, '>')) { |
|
393 | + return $newestVersion; |
|
394 | + } else { |
|
395 | + return false; |
|
396 | + } |
|
397 | + } |
|
398 | + } |
|
399 | + |
|
400 | + return false; |
|
401 | + } |
|
402 | + |
|
403 | + /** |
|
404 | + * Check if app has been installed from git |
|
405 | + * @param string $name name of the application to remove |
|
406 | + * @return boolean |
|
407 | + * |
|
408 | + * The function will check if the path contains a .git folder |
|
409 | + */ |
|
410 | + private function isInstalledFromGit($appId) { |
|
411 | + $app = \OC_App::findAppInDirectories($appId); |
|
412 | + if($app === false) { |
|
413 | + return false; |
|
414 | + } |
|
415 | + $basedir = $app['path'].'/'.$appId; |
|
416 | + return file_exists($basedir.'/.git/'); |
|
417 | + } |
|
418 | + |
|
419 | + /** |
|
420 | + * Check if app is already downloaded |
|
421 | + * @param string $name name of the application to remove |
|
422 | + * @return boolean |
|
423 | + * |
|
424 | + * The function will check if the app is already downloaded in the apps repository |
|
425 | + */ |
|
426 | + public function isDownloaded($name) { |
|
427 | + foreach(\OC::$APPSROOTS as $dir) { |
|
428 | + $dirToTest = $dir['path']; |
|
429 | + $dirToTest .= '/'; |
|
430 | + $dirToTest .= $name; |
|
431 | + $dirToTest .= '/'; |
|
432 | + |
|
433 | + if (is_dir($dirToTest)) { |
|
434 | + return true; |
|
435 | + } |
|
436 | + } |
|
437 | + |
|
438 | + return false; |
|
439 | + } |
|
440 | + |
|
441 | + /** |
|
442 | + * Removes an app |
|
443 | + * @param string $appId ID of the application to remove |
|
444 | + * @return boolean |
|
445 | + * |
|
446 | + * |
|
447 | + * This function works as follows |
|
448 | + * -# call uninstall repair steps |
|
449 | + * -# removing the files |
|
450 | + * |
|
451 | + * The function will not delete preferences, tables and the configuration, |
|
452 | + * this has to be done by the function oc_app_uninstall(). |
|
453 | + */ |
|
454 | + public function removeApp($appId) { |
|
455 | + if($this->isDownloaded( $appId )) { |
|
456 | + if (\OC::$server->getAppManager()->isShipped($appId)) { |
|
457 | + return false; |
|
458 | + } |
|
459 | + $appDir = OC_App::getInstallPath() . '/' . $appId; |
|
460 | + OC_Helper::rmdirr($appDir); |
|
461 | + return true; |
|
462 | + }else{ |
|
463 | + \OCP\Util::writeLog('core', 'can\'t remove app '.$appId.'. It is not installed.', ILogger::ERROR); |
|
464 | + |
|
465 | + return false; |
|
466 | + } |
|
467 | + |
|
468 | + } |
|
469 | + |
|
470 | + /** |
|
471 | + * Installs the app within the bundle and marks the bundle as installed |
|
472 | + * |
|
473 | + * @param Bundle $bundle |
|
474 | + * @throws \Exception If app could not get installed |
|
475 | + */ |
|
476 | + public function installAppBundle(Bundle $bundle) { |
|
477 | + $appIds = $bundle->getAppIdentifiers(); |
|
478 | + foreach($appIds as $appId) { |
|
479 | + if(!$this->isDownloaded($appId)) { |
|
480 | + $this->downloadApp($appId); |
|
481 | + } |
|
482 | + $this->installApp($appId); |
|
483 | + $app = new OC_App(); |
|
484 | + $app->enable($appId); |
|
485 | + } |
|
486 | + $bundles = json_decode($this->config->getAppValue('core', 'installed.bundles', json_encode([])), true); |
|
487 | + $bundles[] = $bundle->getIdentifier(); |
|
488 | + $this->config->setAppValue('core', 'installed.bundles', json_encode($bundles)); |
|
489 | + } |
|
490 | + |
|
491 | + /** |
|
492 | + * Installs shipped apps |
|
493 | + * |
|
494 | + * This function installs all apps found in the 'apps' directory that should be enabled by default; |
|
495 | + * @param bool $softErrors When updating we ignore errors and simply log them, better to have a |
|
496 | + * working ownCloud at the end instead of an aborted update. |
|
497 | + * @return array Array of error messages (appid => Exception) |
|
498 | + */ |
|
499 | + public static function installShippedApps($softErrors = false) { |
|
500 | + $appManager = \OC::$server->getAppManager(); |
|
501 | + $config = \OC::$server->getConfig(); |
|
502 | + $errors = []; |
|
503 | + foreach(\OC::$APPSROOTS as $app_dir) { |
|
504 | + if($dir = opendir( $app_dir['path'] )) { |
|
505 | + while( false !== ( $filename = readdir( $dir ))) { |
|
506 | + if( $filename[0] !== '.' and is_dir($app_dir['path']."/$filename") ) { |
|
507 | + if( file_exists( $app_dir['path']."/$filename/appinfo/info.xml" )) { |
|
508 | + if($config->getAppValue($filename, "installed_version", null) === null) { |
|
509 | + $info=OC_App::getAppInfo($filename); |
|
510 | + $enabled = isset($info['default_enable']); |
|
511 | + if (($enabled || in_array($filename, $appManager->getAlwaysEnabledApps())) |
|
512 | + && $config->getAppValue($filename, 'enabled') !== 'no') { |
|
513 | + if ($softErrors) { |
|
514 | + try { |
|
515 | + Installer::installShippedApp($filename); |
|
516 | + } catch (HintException $e) { |
|
517 | + if ($e->getPrevious() instanceof TableExistsException) { |
|
518 | + $errors[$filename] = $e; |
|
519 | + continue; |
|
520 | + } |
|
521 | + throw $e; |
|
522 | + } |
|
523 | + } else { |
|
524 | + Installer::installShippedApp($filename); |
|
525 | + } |
|
526 | + $config->setAppValue($filename, 'enabled', 'yes'); |
|
527 | + } |
|
528 | + } |
|
529 | + } |
|
530 | + } |
|
531 | + } |
|
532 | + closedir( $dir ); |
|
533 | + } |
|
534 | + } |
|
535 | + |
|
536 | + return $errors; |
|
537 | + } |
|
538 | + |
|
539 | + /** |
|
540 | + * install an app already placed in the app folder |
|
541 | + * @param string $app id of the app to install |
|
542 | + * @return integer |
|
543 | + */ |
|
544 | + public static function installShippedApp($app) { |
|
545 | + //install the database |
|
546 | + $appPath = OC_App::getAppPath($app); |
|
547 | + \OC_App::registerAutoloading($app, $appPath); |
|
548 | + |
|
549 | + if(is_file("$appPath/appinfo/database.xml")) { |
|
550 | + try { |
|
551 | + OC_DB::createDbFromStructure("$appPath/appinfo/database.xml"); |
|
552 | + } catch (TableExistsException $e) { |
|
553 | + throw new HintException( |
|
554 | + 'Failed to enable app ' . $app, |
|
555 | + 'Please ask for help via one of our <a href="https://nextcloud.com/support/" target="_blank" rel="noreferrer noopener">support channels</a>.', |
|
556 | + 0, $e |
|
557 | + ); |
|
558 | + } |
|
559 | + } else { |
|
560 | + $ms = new \OC\DB\MigrationService($app, \OC::$server->getDatabaseConnection()); |
|
561 | + $ms->migrate(); |
|
562 | + } |
|
563 | + |
|
564 | + //run appinfo/install.php |
|
565 | + self::includeAppScript("$appPath/appinfo/install.php"); |
|
566 | + |
|
567 | + $info = OC_App::getAppInfo($app); |
|
568 | + if (is_null($info)) { |
|
569 | + return false; |
|
570 | + } |
|
571 | + \OC_App::setupBackgroundJobs($info['background-jobs']); |
|
572 | + |
|
573 | + OC_App::executeRepairSteps($app, $info['repair-steps']['install']); |
|
574 | + |
|
575 | + $config = \OC::$server->getConfig(); |
|
576 | + |
|
577 | + $config->setAppValue($app, 'installed_version', OC_App::getAppVersion($app)); |
|
578 | + if (array_key_exists('ocsid', $info)) { |
|
579 | + $config->setAppValue($app, 'ocsid', $info['ocsid']); |
|
580 | + } |
|
581 | + |
|
582 | + //set remote/public handlers |
|
583 | + foreach($info['remote'] as $name=>$path) { |
|
584 | + $config->setAppValue('core', 'remote_'.$name, $app.'/'.$path); |
|
585 | + } |
|
586 | + foreach($info['public'] as $name=>$path) { |
|
587 | + $config->setAppValue('core', 'public_'.$name, $app.'/'.$path); |
|
588 | + } |
|
589 | + |
|
590 | + OC_App::setAppTypes($info['id']); |
|
591 | + |
|
592 | + return $info['id']; |
|
593 | + } |
|
594 | + |
|
595 | + /** |
|
596 | + * @param string $script |
|
597 | + */ |
|
598 | + private static function includeAppScript($script) { |
|
599 | + if ( file_exists($script) ){ |
|
600 | + include $script; |
|
601 | + } |
|
602 | + } |
|
603 | 603 | } |
@@ -95,7 +95,7 @@ discard block |
||
95 | 95 | */ |
96 | 96 | public function installApp($appId) { |
97 | 97 | $app = \OC_App::findAppInDirectories($appId); |
98 | - if($app === false) { |
|
98 | + if ($app === false) { |
|
99 | 99 | throw new \Exception('App not found in any app directory'); |
100 | 100 | } |
101 | 101 | |
@@ -104,7 +104,7 @@ discard block |
||
104 | 104 | |
105 | 105 | $l = \OC::$server->getL10N('core'); |
106 | 106 | |
107 | - if(!is_array($info)) { |
|
107 | + if (!is_array($info)) { |
|
108 | 108 | throw new \Exception( |
109 | 109 | $l->t('App "%s" cannot be installed because appinfo file cannot be read.', |
110 | 110 | [$appId] |
@@ -127,7 +127,7 @@ discard block |
||
127 | 127 | \OC_App::registerAutoloading($appId, $basedir); |
128 | 128 | |
129 | 129 | //install the database |
130 | - if(is_file($basedir.'/appinfo/database.xml')) { |
|
130 | + if (is_file($basedir.'/appinfo/database.xml')) { |
|
131 | 131 | if (\OC::$server->getConfig()->getAppValue($info['id'], 'installed_version') === null) { |
132 | 132 | OC_DB::createDbFromStructure($basedir.'/appinfo/database.xml'); |
133 | 133 | } else { |
@@ -141,7 +141,7 @@ discard block |
||
141 | 141 | \OC_App::setupBackgroundJobs($info['background-jobs']); |
142 | 142 | |
143 | 143 | //run appinfo/install.php |
144 | - self::includeAppScript($basedir . '/appinfo/install.php'); |
|
144 | + self::includeAppScript($basedir.'/appinfo/install.php'); |
|
145 | 145 | |
146 | 146 | $appData = OC_App::getAppInfo($appId); |
147 | 147 | OC_App::executeRepairSteps($appId, $appData['repair-steps']['install']); |
@@ -151,10 +151,10 @@ discard block |
||
151 | 151 | \OC::$server->getConfig()->setAppValue($info['id'], 'enabled', 'no'); |
152 | 152 | |
153 | 153 | //set remote/public handlers |
154 | - foreach($info['remote'] as $name=>$path) { |
|
154 | + foreach ($info['remote'] as $name=>$path) { |
|
155 | 155 | \OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $info['id'].'/'.$path); |
156 | 156 | } |
157 | - foreach($info['public'] as $name=>$path) { |
|
157 | + foreach ($info['public'] as $name=>$path) { |
|
158 | 158 | \OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $info['id'].'/'.$path); |
159 | 159 | } |
160 | 160 | |
@@ -170,7 +170,7 @@ discard block |
||
170 | 170 | * @return bool |
171 | 171 | */ |
172 | 172 | public function updateAppstoreApp($appId) { |
173 | - if($this->isUpdateAvailable($appId)) { |
|
173 | + if ($this->isUpdateAvailable($appId)) { |
|
174 | 174 | try { |
175 | 175 | $this->downloadApp($appId); |
176 | 176 | } catch (\Exception $e) { |
@@ -197,18 +197,18 @@ discard block |
||
197 | 197 | $appId = strtolower($appId); |
198 | 198 | |
199 | 199 | $apps = $this->appFetcher->get(); |
200 | - foreach($apps as $app) { |
|
201 | - if($app['id'] === $appId) { |
|
200 | + foreach ($apps as $app) { |
|
201 | + if ($app['id'] === $appId) { |
|
202 | 202 | // Load the certificate |
203 | 203 | $certificate = new X509(); |
204 | - $certificate->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt')); |
|
204 | + $certificate->loadCA(file_get_contents(__DIR__.'/../../resources/codesigning/root.crt')); |
|
205 | 205 | $loadedCertificate = $certificate->loadX509($app['certificate']); |
206 | 206 | |
207 | 207 | // Verify if the certificate has been revoked |
208 | 208 | $crl = new X509(); |
209 | - $crl->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt')); |
|
210 | - $crl->loadCRL(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crl')); |
|
211 | - if($crl->validateSignature() !== true) { |
|
209 | + $crl->loadCA(file_get_contents(__DIR__.'/../../resources/codesigning/root.crt')); |
|
210 | + $crl->loadCRL(file_get_contents(__DIR__.'/../../resources/codesigning/root.crl')); |
|
211 | + if ($crl->validateSignature() !== true) { |
|
212 | 212 | throw new \Exception('Could not validate CRL signature'); |
213 | 213 | } |
214 | 214 | $csn = $loadedCertificate['tbsCertificate']['serialNumber']->toString(); |
@@ -223,7 +223,7 @@ discard block |
||
223 | 223 | } |
224 | 224 | |
225 | 225 | // Verify if the certificate has been issued by the Nextcloud Code Authority CA |
226 | - if($certificate->validateSignature() !== true) { |
|
226 | + if ($certificate->validateSignature() !== true) { |
|
227 | 227 | throw new \Exception( |
228 | 228 | sprintf( |
229 | 229 | 'App with id %s has a certificate not issued by a trusted Code Signing Authority', |
@@ -234,7 +234,7 @@ discard block |
||
234 | 234 | |
235 | 235 | // Verify if the certificate is issued for the requested app id |
236 | 236 | $certInfo = openssl_x509_parse($app['certificate']); |
237 | - if(!isset($certInfo['subject']['CN'])) { |
|
237 | + if (!isset($certInfo['subject']['CN'])) { |
|
238 | 238 | throw new \Exception( |
239 | 239 | sprintf( |
240 | 240 | 'App with id %s has a cert with no CN', |
@@ -242,7 +242,7 @@ discard block |
||
242 | 242 | ) |
243 | 243 | ); |
244 | 244 | } |
245 | - if($certInfo['subject']['CN'] !== $appId) { |
|
245 | + if ($certInfo['subject']['CN'] !== $appId) { |
|
246 | 246 | throw new \Exception( |
247 | 247 | sprintf( |
248 | 248 | 'App with id %s has a cert issued to %s', |
@@ -259,15 +259,15 @@ discard block |
||
259 | 259 | |
260 | 260 | // Check if the signature actually matches the downloaded content |
261 | 261 | $certificate = openssl_get_publickey($app['certificate']); |
262 | - $verified = (bool)openssl_verify(file_get_contents($tempFile), base64_decode($app['releases'][0]['signature']), $certificate, OPENSSL_ALGO_SHA512); |
|
262 | + $verified = (bool) openssl_verify(file_get_contents($tempFile), base64_decode($app['releases'][0]['signature']), $certificate, OPENSSL_ALGO_SHA512); |
|
263 | 263 | openssl_free_key($certificate); |
264 | 264 | |
265 | - if($verified === true) { |
|
265 | + if ($verified === true) { |
|
266 | 266 | // Seems to match, let's proceed |
267 | 267 | $extractDir = $this->tempManager->getTemporaryFolder(); |
268 | 268 | $archive = new TAR($tempFile); |
269 | 269 | |
270 | - if($archive) { |
|
270 | + if ($archive) { |
|
271 | 271 | if (!$archive->extract($extractDir)) { |
272 | 272 | throw new \Exception( |
273 | 273 | sprintf( |
@@ -280,7 +280,7 @@ discard block |
||
280 | 280 | $folders = array_diff($allFiles, ['.', '..']); |
281 | 281 | $folders = array_values($folders); |
282 | 282 | |
283 | - if(count($folders) > 1) { |
|
283 | + if (count($folders) > 1) { |
|
284 | 284 | throw new \Exception( |
285 | 285 | sprintf( |
286 | 286 | 'Extracted app %s has more than 1 folder', |
@@ -291,22 +291,22 @@ discard block |
||
291 | 291 | |
292 | 292 | // Check if appinfo/info.xml has the same app ID as well |
293 | 293 | $loadEntities = libxml_disable_entity_loader(false); |
294 | - $xml = simplexml_load_file($extractDir . '/' . $folders[0] . '/appinfo/info.xml'); |
|
294 | + $xml = simplexml_load_file($extractDir.'/'.$folders[0].'/appinfo/info.xml'); |
|
295 | 295 | libxml_disable_entity_loader($loadEntities); |
296 | - if((string)$xml->id !== $appId) { |
|
296 | + if ((string) $xml->id !== $appId) { |
|
297 | 297 | throw new \Exception( |
298 | 298 | sprintf( |
299 | 299 | 'App for id %s has a wrong app ID in info.xml: %s', |
300 | 300 | $appId, |
301 | - (string)$xml->id |
|
301 | + (string) $xml->id |
|
302 | 302 | ) |
303 | 303 | ); |
304 | 304 | } |
305 | 305 | |
306 | 306 | // Check if the version is lower than before |
307 | 307 | $currentVersion = OC_App::getAppVersion($appId); |
308 | - $newVersion = (string)$xml->version; |
|
309 | - if(version_compare($currentVersion, $newVersion) === 1) { |
|
308 | + $newVersion = (string) $xml->version; |
|
309 | + if (version_compare($currentVersion, $newVersion) === 1) { |
|
310 | 310 | throw new \Exception( |
311 | 311 | sprintf( |
312 | 312 | 'App for id %s has version %s and tried to update to lower version %s', |
@@ -317,12 +317,12 @@ discard block |
||
317 | 317 | ); |
318 | 318 | } |
319 | 319 | |
320 | - $baseDir = OC_App::getInstallPath() . '/' . $appId; |
|
320 | + $baseDir = OC_App::getInstallPath().'/'.$appId; |
|
321 | 321 | // Remove old app with the ID if existent |
322 | 322 | OC_Helper::rmdirr($baseDir); |
323 | 323 | // Move to app folder |
324 | - if(@mkdir($baseDir)) { |
|
325 | - $extractDir .= '/' . $folders[0]; |
|
324 | + if (@mkdir($baseDir)) { |
|
325 | + $extractDir .= '/'.$folders[0]; |
|
326 | 326 | OC_Helper::copyr($extractDir, $baseDir); |
327 | 327 | } |
328 | 328 | OC_Helper::copyr($extractDir, $baseDir); |
@@ -385,8 +385,8 @@ discard block |
||
385 | 385 | $this->apps = $this->appFetcher->get(); |
386 | 386 | } |
387 | 387 | |
388 | - foreach($this->apps as $app) { |
|
389 | - if($app['id'] === $appId) { |
|
388 | + foreach ($this->apps as $app) { |
|
389 | + if ($app['id'] === $appId) { |
|
390 | 390 | $currentVersion = OC_App::getAppVersion($appId); |
391 | 391 | $newestVersion = $app['releases'][0]['version']; |
392 | 392 | if (version_compare($newestVersion, $currentVersion, '>')) { |
@@ -409,7 +409,7 @@ discard block |
||
409 | 409 | */ |
410 | 410 | private function isInstalledFromGit($appId) { |
411 | 411 | $app = \OC_App::findAppInDirectories($appId); |
412 | - if($app === false) { |
|
412 | + if ($app === false) { |
|
413 | 413 | return false; |
414 | 414 | } |
415 | 415 | $basedir = $app['path'].'/'.$appId; |
@@ -424,7 +424,7 @@ discard block |
||
424 | 424 | * The function will check if the app is already downloaded in the apps repository |
425 | 425 | */ |
426 | 426 | public function isDownloaded($name) { |
427 | - foreach(\OC::$APPSROOTS as $dir) { |
|
427 | + foreach (\OC::$APPSROOTS as $dir) { |
|
428 | 428 | $dirToTest = $dir['path']; |
429 | 429 | $dirToTest .= '/'; |
430 | 430 | $dirToTest .= $name; |
@@ -452,14 +452,14 @@ discard block |
||
452 | 452 | * this has to be done by the function oc_app_uninstall(). |
453 | 453 | */ |
454 | 454 | public function removeApp($appId) { |
455 | - if($this->isDownloaded( $appId )) { |
|
455 | + if ($this->isDownloaded($appId)) { |
|
456 | 456 | if (\OC::$server->getAppManager()->isShipped($appId)) { |
457 | 457 | return false; |
458 | 458 | } |
459 | - $appDir = OC_App::getInstallPath() . '/' . $appId; |
|
459 | + $appDir = OC_App::getInstallPath().'/'.$appId; |
|
460 | 460 | OC_Helper::rmdirr($appDir); |
461 | 461 | return true; |
462 | - }else{ |
|
462 | + } else { |
|
463 | 463 | \OCP\Util::writeLog('core', 'can\'t remove app '.$appId.'. It is not installed.', ILogger::ERROR); |
464 | 464 | |
465 | 465 | return false; |
@@ -475,8 +475,8 @@ discard block |
||
475 | 475 | */ |
476 | 476 | public function installAppBundle(Bundle $bundle) { |
477 | 477 | $appIds = $bundle->getAppIdentifiers(); |
478 | - foreach($appIds as $appId) { |
|
479 | - if(!$this->isDownloaded($appId)) { |
|
478 | + foreach ($appIds as $appId) { |
|
479 | + if (!$this->isDownloaded($appId)) { |
|
480 | 480 | $this->downloadApp($appId); |
481 | 481 | } |
482 | 482 | $this->installApp($appId); |
@@ -500,13 +500,13 @@ discard block |
||
500 | 500 | $appManager = \OC::$server->getAppManager(); |
501 | 501 | $config = \OC::$server->getConfig(); |
502 | 502 | $errors = []; |
503 | - foreach(\OC::$APPSROOTS as $app_dir) { |
|
504 | - if($dir = opendir( $app_dir['path'] )) { |
|
505 | - while( false !== ( $filename = readdir( $dir ))) { |
|
506 | - if( $filename[0] !== '.' and is_dir($app_dir['path']."/$filename") ) { |
|
507 | - if( file_exists( $app_dir['path']."/$filename/appinfo/info.xml" )) { |
|
508 | - if($config->getAppValue($filename, "installed_version", null) === null) { |
|
509 | - $info=OC_App::getAppInfo($filename); |
|
503 | + foreach (\OC::$APPSROOTS as $app_dir) { |
|
504 | + if ($dir = opendir($app_dir['path'])) { |
|
505 | + while (false !== ($filename = readdir($dir))) { |
|
506 | + if ($filename[0] !== '.' and is_dir($app_dir['path']."/$filename")) { |
|
507 | + if (file_exists($app_dir['path']."/$filename/appinfo/info.xml")) { |
|
508 | + if ($config->getAppValue($filename, "installed_version", null) === null) { |
|
509 | + $info = OC_App::getAppInfo($filename); |
|
510 | 510 | $enabled = isset($info['default_enable']); |
511 | 511 | if (($enabled || in_array($filename, $appManager->getAlwaysEnabledApps())) |
512 | 512 | && $config->getAppValue($filename, 'enabled') !== 'no') { |
@@ -529,7 +529,7 @@ discard block |
||
529 | 529 | } |
530 | 530 | } |
531 | 531 | } |
532 | - closedir( $dir ); |
|
532 | + closedir($dir); |
|
533 | 533 | } |
534 | 534 | } |
535 | 535 | |
@@ -546,12 +546,12 @@ discard block |
||
546 | 546 | $appPath = OC_App::getAppPath($app); |
547 | 547 | \OC_App::registerAutoloading($app, $appPath); |
548 | 548 | |
549 | - if(is_file("$appPath/appinfo/database.xml")) { |
|
549 | + if (is_file("$appPath/appinfo/database.xml")) { |
|
550 | 550 | try { |
551 | 551 | OC_DB::createDbFromStructure("$appPath/appinfo/database.xml"); |
552 | 552 | } catch (TableExistsException $e) { |
553 | 553 | throw new HintException( |
554 | - 'Failed to enable app ' . $app, |
|
554 | + 'Failed to enable app '.$app, |
|
555 | 555 | 'Please ask for help via one of our <a href="https://nextcloud.com/support/" target="_blank" rel="noreferrer noopener">support channels</a>.', |
556 | 556 | 0, $e |
557 | 557 | ); |
@@ -580,10 +580,10 @@ discard block |
||
580 | 580 | } |
581 | 581 | |
582 | 582 | //set remote/public handlers |
583 | - foreach($info['remote'] as $name=>$path) { |
|
583 | + foreach ($info['remote'] as $name=>$path) { |
|
584 | 584 | $config->setAppValue('core', 'remote_'.$name, $app.'/'.$path); |
585 | 585 | } |
586 | - foreach($info['public'] as $name=>$path) { |
|
586 | + foreach ($info['public'] as $name=>$path) { |
|
587 | 587 | $config->setAppValue('core', 'public_'.$name, $app.'/'.$path); |
588 | 588 | } |
589 | 589 | |
@@ -596,7 +596,7 @@ discard block |
||
596 | 596 | * @param string $script |
597 | 597 | */ |
598 | 598 | private static function includeAppScript($script) { |
599 | - if ( file_exists($script) ){ |
|
599 | + if (file_exists($script)) { |
|
600 | 600 | include $script; |
601 | 601 | } |
602 | 602 | } |
@@ -459,7 +459,7 @@ |
||
459 | 459 | $appDir = OC_App::getInstallPath() . '/' . $appId; |
460 | 460 | OC_Helper::rmdirr($appDir); |
461 | 461 | return true; |
462 | - }else{ |
|
462 | + } else{ |
|
463 | 463 | \OCP\Util::writeLog('core', 'can\'t remove app '.$appId.'. It is not installed.', ILogger::ERROR); |
464 | 464 | |
465 | 465 | return false; |
@@ -57,505 +57,505 @@ |
||
57 | 57 | * @since 4.0.0 |
58 | 58 | */ |
59 | 59 | class Util { |
60 | - /** |
|
61 | - * @deprecated 14.0.0 use \OCP\ILogger::DEBUG |
|
62 | - */ |
|
63 | - const DEBUG=0; |
|
64 | - /** |
|
65 | - * @deprecated 14.0.0 use \OCP\ILogger::INFO |
|
66 | - */ |
|
67 | - const INFO=1; |
|
68 | - /** |
|
69 | - * @deprecated 14.0.0 use \OCP\ILogger::WARN |
|
70 | - */ |
|
71 | - const WARN=2; |
|
72 | - /** |
|
73 | - * @deprecated 14.0.0 use \OCP\ILogger::ERROR |
|
74 | - */ |
|
75 | - const ERROR=3; |
|
76 | - /** |
|
77 | - * @deprecated 14.0.0 use \OCP\ILogger::FATAL |
|
78 | - */ |
|
79 | - const FATAL=4; |
|
80 | - |
|
81 | - /** \OCP\Share\IManager */ |
|
82 | - private static $shareManager; |
|
83 | - |
|
84 | - /** |
|
85 | - * get the current installed version of ownCloud |
|
86 | - * @return array |
|
87 | - * @since 4.0.0 |
|
88 | - */ |
|
89 | - public static function getVersion() { |
|
90 | - return \OC_Util::getVersion(); |
|
91 | - } |
|
60 | + /** |
|
61 | + * @deprecated 14.0.0 use \OCP\ILogger::DEBUG |
|
62 | + */ |
|
63 | + const DEBUG=0; |
|
64 | + /** |
|
65 | + * @deprecated 14.0.0 use \OCP\ILogger::INFO |
|
66 | + */ |
|
67 | + const INFO=1; |
|
68 | + /** |
|
69 | + * @deprecated 14.0.0 use \OCP\ILogger::WARN |
|
70 | + */ |
|
71 | + const WARN=2; |
|
72 | + /** |
|
73 | + * @deprecated 14.0.0 use \OCP\ILogger::ERROR |
|
74 | + */ |
|
75 | + const ERROR=3; |
|
76 | + /** |
|
77 | + * @deprecated 14.0.0 use \OCP\ILogger::FATAL |
|
78 | + */ |
|
79 | + const FATAL=4; |
|
80 | + |
|
81 | + /** \OCP\Share\IManager */ |
|
82 | + private static $shareManager; |
|
83 | + |
|
84 | + /** |
|
85 | + * get the current installed version of ownCloud |
|
86 | + * @return array |
|
87 | + * @since 4.0.0 |
|
88 | + */ |
|
89 | + public static function getVersion() { |
|
90 | + return \OC_Util::getVersion(); |
|
91 | + } |
|
92 | 92 | |
93 | - /** |
|
94 | - * Set current update channel |
|
95 | - * @param string $channel |
|
96 | - * @since 8.1.0 |
|
97 | - */ |
|
98 | - public static function setChannel($channel) { |
|
99 | - \OC::$server->getConfig()->setSystemValue('updater.release.channel', $channel); |
|
100 | - } |
|
93 | + /** |
|
94 | + * Set current update channel |
|
95 | + * @param string $channel |
|
96 | + * @since 8.1.0 |
|
97 | + */ |
|
98 | + public static function setChannel($channel) { |
|
99 | + \OC::$server->getConfig()->setSystemValue('updater.release.channel', $channel); |
|
100 | + } |
|
101 | 101 | |
102 | - /** |
|
103 | - * Get current update channel |
|
104 | - * @return string |
|
105 | - * @since 8.1.0 |
|
106 | - */ |
|
107 | - public static function getChannel() { |
|
108 | - return \OC_Util::getChannel(); |
|
109 | - } |
|
110 | - |
|
111 | - /** |
|
112 | - * write a message in the log |
|
113 | - * @param string $app |
|
114 | - * @param string $message |
|
115 | - * @param int $level |
|
116 | - * @since 4.0.0 |
|
117 | - * @deprecated 13.0.0 use log of \OCP\ILogger |
|
118 | - */ |
|
119 | - public static function writeLog( $app, $message, $level ) { |
|
120 | - $context = ['app' => $app]; |
|
121 | - \OC::$server->getLogger()->log($level, $message, $context); |
|
122 | - } |
|
123 | - |
|
124 | - /** |
|
125 | - * write exception into the log |
|
126 | - * @param string $app app name |
|
127 | - * @param \Exception $ex exception to log |
|
128 | - * @param int $level log level, defaults to \OCP\Util::FATAL |
|
129 | - * @since ....0.0 - parameter $level was added in 7.0.0 |
|
130 | - * @deprecated 8.2.0 use logException of \OCP\ILogger |
|
131 | - */ |
|
132 | - public static function logException( $app, \Exception $ex, $level = ILogger::FATAL) { |
|
133 | - \OC::$server->getLogger()->logException($ex, ['app' => $app]); |
|
134 | - } |
|
135 | - |
|
136 | - /** |
|
137 | - * check if sharing is disabled for the current user |
|
138 | - * |
|
139 | - * @return boolean |
|
140 | - * @since 7.0.0 |
|
141 | - * @deprecated 9.1.0 Use \OC::$server->getShareManager()->sharingDisabledForUser |
|
142 | - */ |
|
143 | - public static function isSharingDisabledForUser() { |
|
144 | - if (self::$shareManager === null) { |
|
145 | - self::$shareManager = \OC::$server->getShareManager(); |
|
146 | - } |
|
147 | - |
|
148 | - $user = \OC::$server->getUserSession()->getUser(); |
|
149 | - if ($user !== null) { |
|
150 | - $user = $user->getUID(); |
|
151 | - } |
|
152 | - |
|
153 | - return self::$shareManager->sharingDisabledForUser($user); |
|
154 | - } |
|
155 | - |
|
156 | - /** |
|
157 | - * get l10n object |
|
158 | - * @param string $application |
|
159 | - * @param string|null $language |
|
160 | - * @return \OCP\IL10N |
|
161 | - * @since 6.0.0 - parameter $language was added in 8.0.0 |
|
162 | - */ |
|
163 | - public static function getL10N($application, $language = null) { |
|
164 | - return \OC::$server->getL10N($application, $language); |
|
165 | - } |
|
166 | - |
|
167 | - /** |
|
168 | - * add a css file |
|
169 | - * @param string $application |
|
170 | - * @param string $file |
|
171 | - * @since 4.0.0 |
|
172 | - */ |
|
173 | - public static function addStyle( $application, $file = null ) { |
|
174 | - \OC_Util::addStyle( $application, $file ); |
|
175 | - } |
|
176 | - |
|
177 | - /** |
|
178 | - * add a javascript file |
|
179 | - * @param string $application |
|
180 | - * @param string $file |
|
181 | - * @since 4.0.0 |
|
182 | - */ |
|
183 | - public static function addScript( $application, $file = null ) { |
|
184 | - \OC_Util::addScript( $application, $file ); |
|
185 | - } |
|
186 | - |
|
187 | - /** |
|
188 | - * Add a translation JS file |
|
189 | - * @param string $application application id |
|
190 | - * @param string $languageCode language code, defaults to the current locale |
|
191 | - * @since 8.0.0 |
|
192 | - */ |
|
193 | - public static function addTranslations($application, $languageCode = null) { |
|
194 | - \OC_Util::addTranslations($application, $languageCode); |
|
195 | - } |
|
196 | - |
|
197 | - /** |
|
198 | - * Add a custom element to the header |
|
199 | - * If $text is null then the element will be written as empty element. |
|
200 | - * So use "" to get a closing tag. |
|
201 | - * @param string $tag tag name of the element |
|
202 | - * @param array $attributes array of attributes for the element |
|
203 | - * @param string $text the text content for the element |
|
204 | - * @since 4.0.0 |
|
205 | - */ |
|
206 | - public static function addHeader($tag, $attributes, $text=null) { |
|
207 | - \OC_Util::addHeader($tag, $attributes, $text); |
|
208 | - } |
|
209 | - |
|
210 | - /** |
|
211 | - * Creates an absolute url to the given app and file. |
|
212 | - * @param string $app app |
|
213 | - * @param string $file file |
|
214 | - * @param array $args array with param=>value, will be appended to the returned url |
|
215 | - * The value of $args will be urlencoded |
|
216 | - * @return string the url |
|
217 | - * @since 4.0.0 - parameter $args was added in 4.5.0 |
|
218 | - */ |
|
219 | - public static function linkToAbsolute( $app, $file, $args = array() ) { |
|
220 | - $urlGenerator = \OC::$server->getURLGenerator(); |
|
221 | - return $urlGenerator->getAbsoluteURL( |
|
222 | - $urlGenerator->linkTo($app, $file, $args) |
|
223 | - ); |
|
224 | - } |
|
225 | - |
|
226 | - /** |
|
227 | - * Creates an absolute url for remote use. |
|
228 | - * @param string $service id |
|
229 | - * @return string the url |
|
230 | - * @since 4.0.0 |
|
231 | - */ |
|
232 | - public static function linkToRemote( $service ) { |
|
233 | - $urlGenerator = \OC::$server->getURLGenerator(); |
|
234 | - $remoteBase = $urlGenerator->linkTo('', 'remote.php') . '/' . $service; |
|
235 | - return $urlGenerator->getAbsoluteURL( |
|
236 | - $remoteBase . (($service[strlen($service) - 1] != '/') ? '/' : '') |
|
237 | - ); |
|
238 | - } |
|
239 | - |
|
240 | - /** |
|
241 | - * Creates an absolute url for public use |
|
242 | - * @param string $service id |
|
243 | - * @return string the url |
|
244 | - * @since 4.5.0 |
|
245 | - */ |
|
246 | - public static function linkToPublic($service) { |
|
247 | - return \OC_Helper::linkToPublic($service); |
|
248 | - } |
|
249 | - |
|
250 | - /** |
|
251 | - * Returns the server host name without an eventual port number |
|
252 | - * @return string the server hostname |
|
253 | - * @since 5.0.0 |
|
254 | - */ |
|
255 | - public static function getServerHostName() { |
|
256 | - $host_name = \OC::$server->getRequest()->getServerHost(); |
|
257 | - // strip away port number (if existing) |
|
258 | - $colon_pos = strpos($host_name, ':'); |
|
259 | - if ($colon_pos != FALSE) { |
|
260 | - $host_name = substr($host_name, 0, $colon_pos); |
|
261 | - } |
|
262 | - return $host_name; |
|
263 | - } |
|
264 | - |
|
265 | - /** |
|
266 | - * Returns the default email address |
|
267 | - * @param string $user_part the user part of the address |
|
268 | - * @return string the default email address |
|
269 | - * |
|
270 | - * Assembles a default email address (using the server hostname |
|
271 | - * and the given user part, and returns it |
|
272 | - * Example: when given lostpassword-noreply as $user_part param, |
|
273 | - * and is currently accessed via http(s)://example.com/, |
|
274 | - * it would return '[email protected]' |
|
275 | - * |
|
276 | - * If the configuration value 'mail_from_address' is set in |
|
277 | - * config.php, this value will override the $user_part that |
|
278 | - * is passed to this function |
|
279 | - * @since 5.0.0 |
|
280 | - */ |
|
281 | - public static function getDefaultEmailAddress($user_part) { |
|
282 | - $config = \OC::$server->getConfig(); |
|
283 | - $user_part = $config->getSystemValue('mail_from_address', $user_part); |
|
284 | - $host_name = self::getServerHostName(); |
|
285 | - $host_name = $config->getSystemValue('mail_domain', $host_name); |
|
286 | - $defaultEmailAddress = $user_part.'@'.$host_name; |
|
287 | - |
|
288 | - $mailer = \OC::$server->getMailer(); |
|
289 | - if ($mailer->validateMailAddress($defaultEmailAddress)) { |
|
290 | - return $defaultEmailAddress; |
|
291 | - } |
|
292 | - |
|
293 | - // in case we cannot build a valid email address from the hostname let's fallback to 'localhost.localdomain' |
|
294 | - return $user_part.'@localhost.localdomain'; |
|
295 | - } |
|
296 | - |
|
297 | - /** |
|
298 | - * Make a human file size (2048 to 2 kB) |
|
299 | - * @param int $bytes file size in bytes |
|
300 | - * @return string a human readable file size |
|
301 | - * @since 4.0.0 |
|
302 | - */ |
|
303 | - public static function humanFileSize($bytes) { |
|
304 | - return \OC_Helper::humanFileSize($bytes); |
|
305 | - } |
|
306 | - |
|
307 | - /** |
|
308 | - * Make a computer file size (2 kB to 2048) |
|
309 | - * @param string $str file size in a fancy format |
|
310 | - * @return float a file size in bytes |
|
311 | - * |
|
312 | - * Inspired by: http://www.php.net/manual/en/function.filesize.php#92418 |
|
313 | - * @since 4.0.0 |
|
314 | - */ |
|
315 | - public static function computerFileSize($str) { |
|
316 | - return \OC_Helper::computerFileSize($str); |
|
317 | - } |
|
318 | - |
|
319 | - /** |
|
320 | - * connects a function to a hook |
|
321 | - * |
|
322 | - * @param string $signalClass class name of emitter |
|
323 | - * @param string $signalName name of signal |
|
324 | - * @param string|object $slotClass class name of slot |
|
325 | - * @param string $slotName name of slot |
|
326 | - * @return bool |
|
327 | - * |
|
328 | - * This function makes it very easy to connect to use hooks. |
|
329 | - * |
|
330 | - * TODO: write example |
|
331 | - * @since 4.0.0 |
|
332 | - */ |
|
333 | - static public function connectHook($signalClass, $signalName, $slotClass, $slotName) { |
|
334 | - return \OC_Hook::connect($signalClass, $signalName, $slotClass, $slotName); |
|
335 | - } |
|
336 | - |
|
337 | - /** |
|
338 | - * Emits a signal. To get data from the slot use references! |
|
339 | - * @param string $signalclass class name of emitter |
|
340 | - * @param string $signalname name of signal |
|
341 | - * @param array $params default: array() array with additional data |
|
342 | - * @return bool true if slots exists or false if not |
|
343 | - * |
|
344 | - * TODO: write example |
|
345 | - * @since 4.0.0 |
|
346 | - */ |
|
347 | - static public function emitHook($signalclass, $signalname, $params = array()) { |
|
348 | - return \OC_Hook::emit($signalclass, $signalname, $params); |
|
349 | - } |
|
350 | - |
|
351 | - /** |
|
352 | - * Cached encrypted CSRF token. Some static unit-tests of ownCloud compare |
|
353 | - * multiple OC_Template elements which invoke `callRegister`. If the value |
|
354 | - * would not be cached these unit-tests would fail. |
|
355 | - * @var string |
|
356 | - */ |
|
357 | - private static $token = ''; |
|
358 | - |
|
359 | - /** |
|
360 | - * Register an get/post call. This is important to prevent CSRF attacks |
|
361 | - * @since 4.5.0 |
|
362 | - */ |
|
363 | - public static function callRegister() { |
|
364 | - if(self::$token === '') { |
|
365 | - self::$token = \OC::$server->getCsrfTokenManager()->getToken()->getEncryptedValue(); |
|
366 | - } |
|
367 | - return self::$token; |
|
368 | - } |
|
369 | - |
|
370 | - /** |
|
371 | - * Check an ajax get/post call if the request token is valid. exit if not. |
|
372 | - * @since 4.5.0 |
|
373 | - * @deprecated 9.0.0 Use annotations based on the app framework. |
|
374 | - */ |
|
375 | - public static function callCheck() { |
|
376 | - if(!\OC::$server->getRequest()->passesStrictCookieCheck()) { |
|
377 | - header('Location: '.\OC::$WEBROOT); |
|
378 | - exit(); |
|
379 | - } |
|
380 | - |
|
381 | - if (!\OC::$server->getRequest()->passesCSRFCheck()) { |
|
382 | - exit(); |
|
383 | - } |
|
384 | - } |
|
385 | - |
|
386 | - /** |
|
387 | - * Used to sanitize HTML |
|
388 | - * |
|
389 | - * This function is used to sanitize HTML and should be applied on any |
|
390 | - * string or array of strings before displaying it on a web page. |
|
391 | - * |
|
392 | - * @param string|array $value |
|
393 | - * @return string|array an array of sanitized strings or a single sanitized string, depends on the input parameter. |
|
394 | - * @since 4.5.0 |
|
395 | - */ |
|
396 | - public static function sanitizeHTML($value) { |
|
397 | - return \OC_Util::sanitizeHTML($value); |
|
398 | - } |
|
399 | - |
|
400 | - /** |
|
401 | - * Public function to encode url parameters |
|
402 | - * |
|
403 | - * This function is used to encode path to file before output. |
|
404 | - * Encoding is done according to RFC 3986 with one exception: |
|
405 | - * Character '/' is preserved as is. |
|
406 | - * |
|
407 | - * @param string $component part of URI to encode |
|
408 | - * @return string |
|
409 | - * @since 6.0.0 |
|
410 | - */ |
|
411 | - public static function encodePath($component) { |
|
412 | - return \OC_Util::encodePath($component); |
|
413 | - } |
|
414 | - |
|
415 | - /** |
|
416 | - * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is. |
|
417 | - * |
|
418 | - * @param array $input The array to work on |
|
419 | - * @param int $case Either MB_CASE_UPPER or MB_CASE_LOWER (default) |
|
420 | - * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8 |
|
421 | - * @return array |
|
422 | - * @since 4.5.0 |
|
423 | - */ |
|
424 | - public static function mb_array_change_key_case($input, $case = MB_CASE_LOWER, $encoding = 'UTF-8') { |
|
425 | - return \OC_Helper::mb_array_change_key_case($input, $case, $encoding); |
|
426 | - } |
|
427 | - |
|
428 | - /** |
|
429 | - * replaces a copy of string delimited by the start and (optionally) length parameters with the string given in replacement. |
|
430 | - * |
|
431 | - * @param string $string The input string. Opposite to the PHP build-in function does not accept an array. |
|
432 | - * @param string $replacement The replacement string. |
|
433 | - * @param int $start If start is positive, the replacing will begin at the start'th offset into string. If start is negative, the replacing will begin at the start'th character from the end of string. |
|
434 | - * @param int $length Length of the part to be replaced |
|
435 | - * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8 |
|
436 | - * @return string |
|
437 | - * @since 4.5.0 |
|
438 | - * @deprecated 8.2.0 Use substr_replace() instead. |
|
439 | - */ |
|
440 | - public static function mb_substr_replace($string, $replacement, $start, $length = null, $encoding = 'UTF-8') { |
|
441 | - return substr_replace($string, $replacement, $start, $length); |
|
442 | - } |
|
443 | - |
|
444 | - /** |
|
445 | - * Replace all occurrences of the search string with the replacement string |
|
446 | - * |
|
447 | - * @param string $search The value being searched for, otherwise known as the needle. String. |
|
448 | - * @param string $replace The replacement string. |
|
449 | - * @param string $subject The string or array being searched and replaced on, otherwise known as the haystack. |
|
450 | - * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8 |
|
451 | - * @param int $count If passed, this will be set to the number of replacements performed. |
|
452 | - * @return string |
|
453 | - * @since 4.5.0 |
|
454 | - * @deprecated 8.2.0 Use str_replace() instead. |
|
455 | - */ |
|
456 | - public static function mb_str_replace($search, $replace, $subject, $encoding = 'UTF-8', &$count = null) { |
|
457 | - return str_replace($search, $replace, $subject, $count); |
|
458 | - } |
|
459 | - |
|
460 | - /** |
|
461 | - * performs a search in a nested array |
|
462 | - * |
|
463 | - * @param array $haystack the array to be searched |
|
464 | - * @param string $needle the search string |
|
465 | - * @param mixed $index optional, only search this key name |
|
466 | - * @return mixed the key of the matching field, otherwise false |
|
467 | - * @since 4.5.0 |
|
468 | - */ |
|
469 | - public static function recursiveArraySearch($haystack, $needle, $index = null) { |
|
470 | - return \OC_Helper::recursiveArraySearch($haystack, $needle, $index); |
|
471 | - } |
|
472 | - |
|
473 | - /** |
|
474 | - * calculates the maximum upload size respecting system settings, free space and user quota |
|
475 | - * |
|
476 | - * @param string $dir the current folder where the user currently operates |
|
477 | - * @param int $free the number of bytes free on the storage holding $dir, if not set this will be received from the storage directly |
|
478 | - * @return int number of bytes representing |
|
479 | - * @since 5.0.0 |
|
480 | - */ |
|
481 | - public static function maxUploadFilesize($dir, $free = null) { |
|
482 | - return \OC_Helper::maxUploadFilesize($dir, $free); |
|
483 | - } |
|
484 | - |
|
485 | - /** |
|
486 | - * Calculate free space left within user quota |
|
487 | - * @param string $dir the current folder where the user currently operates |
|
488 | - * @return int number of bytes representing |
|
489 | - * @since 7.0.0 |
|
490 | - */ |
|
491 | - public static function freeSpace($dir) { |
|
492 | - return \OC_Helper::freeSpace($dir); |
|
493 | - } |
|
494 | - |
|
495 | - /** |
|
496 | - * Calculate PHP upload limit |
|
497 | - * |
|
498 | - * @return int number of bytes representing |
|
499 | - * @since 7.0.0 |
|
500 | - */ |
|
501 | - public static function uploadLimit() { |
|
502 | - return \OC_Helper::uploadLimit(); |
|
503 | - } |
|
504 | - |
|
505 | - /** |
|
506 | - * Returns whether the given file name is valid |
|
507 | - * @param string $file file name to check |
|
508 | - * @return bool true if the file name is valid, false otherwise |
|
509 | - * @deprecated 8.1.0 use \OC\Files\View::verifyPath() |
|
510 | - * @since 7.0.0 |
|
511 | - * @suppress PhanDeprecatedFunction |
|
512 | - */ |
|
513 | - public static function isValidFileName($file) { |
|
514 | - return \OC_Util::isValidFileName($file); |
|
515 | - } |
|
516 | - |
|
517 | - /** |
|
518 | - * Compare two strings to provide a natural sort |
|
519 | - * @param string $a first string to compare |
|
520 | - * @param string $b second string to compare |
|
521 | - * @return int -1 if $b comes before $a, 1 if $a comes before $b |
|
522 | - * or 0 if the strings are identical |
|
523 | - * @since 7.0.0 |
|
524 | - */ |
|
525 | - public static function naturalSortCompare($a, $b) { |
|
526 | - return \OC\NaturalSort::getInstance()->compare($a, $b); |
|
527 | - } |
|
528 | - |
|
529 | - /** |
|
530 | - * check if a password is required for each public link |
|
531 | - * @return boolean |
|
532 | - * @since 7.0.0 |
|
533 | - */ |
|
534 | - public static function isPublicLinkPasswordRequired() { |
|
535 | - return \OC_Util::isPublicLinkPasswordRequired(); |
|
536 | - } |
|
537 | - |
|
538 | - /** |
|
539 | - * check if share API enforces a default expire date |
|
540 | - * @return boolean |
|
541 | - * @since 8.0.0 |
|
542 | - */ |
|
543 | - public static function isDefaultExpireDateEnforced() { |
|
544 | - return \OC_Util::isDefaultExpireDateEnforced(); |
|
545 | - } |
|
546 | - |
|
547 | - protected static $needUpgradeCache = null; |
|
548 | - |
|
549 | - /** |
|
550 | - * Checks whether the current version needs upgrade. |
|
551 | - * |
|
552 | - * @return bool true if upgrade is needed, false otherwise |
|
553 | - * @since 7.0.0 |
|
554 | - */ |
|
555 | - public static function needUpgrade() { |
|
556 | - if (!isset(self::$needUpgradeCache)) { |
|
557 | - self::$needUpgradeCache=\OC_Util::needUpgrade(\OC::$server->getSystemConfig()); |
|
558 | - } |
|
559 | - return self::$needUpgradeCache; |
|
560 | - } |
|
102 | + /** |
|
103 | + * Get current update channel |
|
104 | + * @return string |
|
105 | + * @since 8.1.0 |
|
106 | + */ |
|
107 | + public static function getChannel() { |
|
108 | + return \OC_Util::getChannel(); |
|
109 | + } |
|
110 | + |
|
111 | + /** |
|
112 | + * write a message in the log |
|
113 | + * @param string $app |
|
114 | + * @param string $message |
|
115 | + * @param int $level |
|
116 | + * @since 4.0.0 |
|
117 | + * @deprecated 13.0.0 use log of \OCP\ILogger |
|
118 | + */ |
|
119 | + public static function writeLog( $app, $message, $level ) { |
|
120 | + $context = ['app' => $app]; |
|
121 | + \OC::$server->getLogger()->log($level, $message, $context); |
|
122 | + } |
|
123 | + |
|
124 | + /** |
|
125 | + * write exception into the log |
|
126 | + * @param string $app app name |
|
127 | + * @param \Exception $ex exception to log |
|
128 | + * @param int $level log level, defaults to \OCP\Util::FATAL |
|
129 | + * @since ....0.0 - parameter $level was added in 7.0.0 |
|
130 | + * @deprecated 8.2.0 use logException of \OCP\ILogger |
|
131 | + */ |
|
132 | + public static function logException( $app, \Exception $ex, $level = ILogger::FATAL) { |
|
133 | + \OC::$server->getLogger()->logException($ex, ['app' => $app]); |
|
134 | + } |
|
135 | + |
|
136 | + /** |
|
137 | + * check if sharing is disabled for the current user |
|
138 | + * |
|
139 | + * @return boolean |
|
140 | + * @since 7.0.0 |
|
141 | + * @deprecated 9.1.0 Use \OC::$server->getShareManager()->sharingDisabledForUser |
|
142 | + */ |
|
143 | + public static function isSharingDisabledForUser() { |
|
144 | + if (self::$shareManager === null) { |
|
145 | + self::$shareManager = \OC::$server->getShareManager(); |
|
146 | + } |
|
147 | + |
|
148 | + $user = \OC::$server->getUserSession()->getUser(); |
|
149 | + if ($user !== null) { |
|
150 | + $user = $user->getUID(); |
|
151 | + } |
|
152 | + |
|
153 | + return self::$shareManager->sharingDisabledForUser($user); |
|
154 | + } |
|
155 | + |
|
156 | + /** |
|
157 | + * get l10n object |
|
158 | + * @param string $application |
|
159 | + * @param string|null $language |
|
160 | + * @return \OCP\IL10N |
|
161 | + * @since 6.0.0 - parameter $language was added in 8.0.0 |
|
162 | + */ |
|
163 | + public static function getL10N($application, $language = null) { |
|
164 | + return \OC::$server->getL10N($application, $language); |
|
165 | + } |
|
166 | + |
|
167 | + /** |
|
168 | + * add a css file |
|
169 | + * @param string $application |
|
170 | + * @param string $file |
|
171 | + * @since 4.0.0 |
|
172 | + */ |
|
173 | + public static function addStyle( $application, $file = null ) { |
|
174 | + \OC_Util::addStyle( $application, $file ); |
|
175 | + } |
|
176 | + |
|
177 | + /** |
|
178 | + * add a javascript file |
|
179 | + * @param string $application |
|
180 | + * @param string $file |
|
181 | + * @since 4.0.0 |
|
182 | + */ |
|
183 | + public static function addScript( $application, $file = null ) { |
|
184 | + \OC_Util::addScript( $application, $file ); |
|
185 | + } |
|
186 | + |
|
187 | + /** |
|
188 | + * Add a translation JS file |
|
189 | + * @param string $application application id |
|
190 | + * @param string $languageCode language code, defaults to the current locale |
|
191 | + * @since 8.0.0 |
|
192 | + */ |
|
193 | + public static function addTranslations($application, $languageCode = null) { |
|
194 | + \OC_Util::addTranslations($application, $languageCode); |
|
195 | + } |
|
196 | + |
|
197 | + /** |
|
198 | + * Add a custom element to the header |
|
199 | + * If $text is null then the element will be written as empty element. |
|
200 | + * So use "" to get a closing tag. |
|
201 | + * @param string $tag tag name of the element |
|
202 | + * @param array $attributes array of attributes for the element |
|
203 | + * @param string $text the text content for the element |
|
204 | + * @since 4.0.0 |
|
205 | + */ |
|
206 | + public static function addHeader($tag, $attributes, $text=null) { |
|
207 | + \OC_Util::addHeader($tag, $attributes, $text); |
|
208 | + } |
|
209 | + |
|
210 | + /** |
|
211 | + * Creates an absolute url to the given app and file. |
|
212 | + * @param string $app app |
|
213 | + * @param string $file file |
|
214 | + * @param array $args array with param=>value, will be appended to the returned url |
|
215 | + * The value of $args will be urlencoded |
|
216 | + * @return string the url |
|
217 | + * @since 4.0.0 - parameter $args was added in 4.5.0 |
|
218 | + */ |
|
219 | + public static function linkToAbsolute( $app, $file, $args = array() ) { |
|
220 | + $urlGenerator = \OC::$server->getURLGenerator(); |
|
221 | + return $urlGenerator->getAbsoluteURL( |
|
222 | + $urlGenerator->linkTo($app, $file, $args) |
|
223 | + ); |
|
224 | + } |
|
225 | + |
|
226 | + /** |
|
227 | + * Creates an absolute url for remote use. |
|
228 | + * @param string $service id |
|
229 | + * @return string the url |
|
230 | + * @since 4.0.0 |
|
231 | + */ |
|
232 | + public static function linkToRemote( $service ) { |
|
233 | + $urlGenerator = \OC::$server->getURLGenerator(); |
|
234 | + $remoteBase = $urlGenerator->linkTo('', 'remote.php') . '/' . $service; |
|
235 | + return $urlGenerator->getAbsoluteURL( |
|
236 | + $remoteBase . (($service[strlen($service) - 1] != '/') ? '/' : '') |
|
237 | + ); |
|
238 | + } |
|
239 | + |
|
240 | + /** |
|
241 | + * Creates an absolute url for public use |
|
242 | + * @param string $service id |
|
243 | + * @return string the url |
|
244 | + * @since 4.5.0 |
|
245 | + */ |
|
246 | + public static function linkToPublic($service) { |
|
247 | + return \OC_Helper::linkToPublic($service); |
|
248 | + } |
|
249 | + |
|
250 | + /** |
|
251 | + * Returns the server host name without an eventual port number |
|
252 | + * @return string the server hostname |
|
253 | + * @since 5.0.0 |
|
254 | + */ |
|
255 | + public static function getServerHostName() { |
|
256 | + $host_name = \OC::$server->getRequest()->getServerHost(); |
|
257 | + // strip away port number (if existing) |
|
258 | + $colon_pos = strpos($host_name, ':'); |
|
259 | + if ($colon_pos != FALSE) { |
|
260 | + $host_name = substr($host_name, 0, $colon_pos); |
|
261 | + } |
|
262 | + return $host_name; |
|
263 | + } |
|
264 | + |
|
265 | + /** |
|
266 | + * Returns the default email address |
|
267 | + * @param string $user_part the user part of the address |
|
268 | + * @return string the default email address |
|
269 | + * |
|
270 | + * Assembles a default email address (using the server hostname |
|
271 | + * and the given user part, and returns it |
|
272 | + * Example: when given lostpassword-noreply as $user_part param, |
|
273 | + * and is currently accessed via http(s)://example.com/, |
|
274 | + * it would return '[email protected]' |
|
275 | + * |
|
276 | + * If the configuration value 'mail_from_address' is set in |
|
277 | + * config.php, this value will override the $user_part that |
|
278 | + * is passed to this function |
|
279 | + * @since 5.0.0 |
|
280 | + */ |
|
281 | + public static function getDefaultEmailAddress($user_part) { |
|
282 | + $config = \OC::$server->getConfig(); |
|
283 | + $user_part = $config->getSystemValue('mail_from_address', $user_part); |
|
284 | + $host_name = self::getServerHostName(); |
|
285 | + $host_name = $config->getSystemValue('mail_domain', $host_name); |
|
286 | + $defaultEmailAddress = $user_part.'@'.$host_name; |
|
287 | + |
|
288 | + $mailer = \OC::$server->getMailer(); |
|
289 | + if ($mailer->validateMailAddress($defaultEmailAddress)) { |
|
290 | + return $defaultEmailAddress; |
|
291 | + } |
|
292 | + |
|
293 | + // in case we cannot build a valid email address from the hostname let's fallback to 'localhost.localdomain' |
|
294 | + return $user_part.'@localhost.localdomain'; |
|
295 | + } |
|
296 | + |
|
297 | + /** |
|
298 | + * Make a human file size (2048 to 2 kB) |
|
299 | + * @param int $bytes file size in bytes |
|
300 | + * @return string a human readable file size |
|
301 | + * @since 4.0.0 |
|
302 | + */ |
|
303 | + public static function humanFileSize($bytes) { |
|
304 | + return \OC_Helper::humanFileSize($bytes); |
|
305 | + } |
|
306 | + |
|
307 | + /** |
|
308 | + * Make a computer file size (2 kB to 2048) |
|
309 | + * @param string $str file size in a fancy format |
|
310 | + * @return float a file size in bytes |
|
311 | + * |
|
312 | + * Inspired by: http://www.php.net/manual/en/function.filesize.php#92418 |
|
313 | + * @since 4.0.0 |
|
314 | + */ |
|
315 | + public static function computerFileSize($str) { |
|
316 | + return \OC_Helper::computerFileSize($str); |
|
317 | + } |
|
318 | + |
|
319 | + /** |
|
320 | + * connects a function to a hook |
|
321 | + * |
|
322 | + * @param string $signalClass class name of emitter |
|
323 | + * @param string $signalName name of signal |
|
324 | + * @param string|object $slotClass class name of slot |
|
325 | + * @param string $slotName name of slot |
|
326 | + * @return bool |
|
327 | + * |
|
328 | + * This function makes it very easy to connect to use hooks. |
|
329 | + * |
|
330 | + * TODO: write example |
|
331 | + * @since 4.0.0 |
|
332 | + */ |
|
333 | + static public function connectHook($signalClass, $signalName, $slotClass, $slotName) { |
|
334 | + return \OC_Hook::connect($signalClass, $signalName, $slotClass, $slotName); |
|
335 | + } |
|
336 | + |
|
337 | + /** |
|
338 | + * Emits a signal. To get data from the slot use references! |
|
339 | + * @param string $signalclass class name of emitter |
|
340 | + * @param string $signalname name of signal |
|
341 | + * @param array $params default: array() array with additional data |
|
342 | + * @return bool true if slots exists or false if not |
|
343 | + * |
|
344 | + * TODO: write example |
|
345 | + * @since 4.0.0 |
|
346 | + */ |
|
347 | + static public function emitHook($signalclass, $signalname, $params = array()) { |
|
348 | + return \OC_Hook::emit($signalclass, $signalname, $params); |
|
349 | + } |
|
350 | + |
|
351 | + /** |
|
352 | + * Cached encrypted CSRF token. Some static unit-tests of ownCloud compare |
|
353 | + * multiple OC_Template elements which invoke `callRegister`. If the value |
|
354 | + * would not be cached these unit-tests would fail. |
|
355 | + * @var string |
|
356 | + */ |
|
357 | + private static $token = ''; |
|
358 | + |
|
359 | + /** |
|
360 | + * Register an get/post call. This is important to prevent CSRF attacks |
|
361 | + * @since 4.5.0 |
|
362 | + */ |
|
363 | + public static function callRegister() { |
|
364 | + if(self::$token === '') { |
|
365 | + self::$token = \OC::$server->getCsrfTokenManager()->getToken()->getEncryptedValue(); |
|
366 | + } |
|
367 | + return self::$token; |
|
368 | + } |
|
369 | + |
|
370 | + /** |
|
371 | + * Check an ajax get/post call if the request token is valid. exit if not. |
|
372 | + * @since 4.5.0 |
|
373 | + * @deprecated 9.0.0 Use annotations based on the app framework. |
|
374 | + */ |
|
375 | + public static function callCheck() { |
|
376 | + if(!\OC::$server->getRequest()->passesStrictCookieCheck()) { |
|
377 | + header('Location: '.\OC::$WEBROOT); |
|
378 | + exit(); |
|
379 | + } |
|
380 | + |
|
381 | + if (!\OC::$server->getRequest()->passesCSRFCheck()) { |
|
382 | + exit(); |
|
383 | + } |
|
384 | + } |
|
385 | + |
|
386 | + /** |
|
387 | + * Used to sanitize HTML |
|
388 | + * |
|
389 | + * This function is used to sanitize HTML and should be applied on any |
|
390 | + * string or array of strings before displaying it on a web page. |
|
391 | + * |
|
392 | + * @param string|array $value |
|
393 | + * @return string|array an array of sanitized strings or a single sanitized string, depends on the input parameter. |
|
394 | + * @since 4.5.0 |
|
395 | + */ |
|
396 | + public static function sanitizeHTML($value) { |
|
397 | + return \OC_Util::sanitizeHTML($value); |
|
398 | + } |
|
399 | + |
|
400 | + /** |
|
401 | + * Public function to encode url parameters |
|
402 | + * |
|
403 | + * This function is used to encode path to file before output. |
|
404 | + * Encoding is done according to RFC 3986 with one exception: |
|
405 | + * Character '/' is preserved as is. |
|
406 | + * |
|
407 | + * @param string $component part of URI to encode |
|
408 | + * @return string |
|
409 | + * @since 6.0.0 |
|
410 | + */ |
|
411 | + public static function encodePath($component) { |
|
412 | + return \OC_Util::encodePath($component); |
|
413 | + } |
|
414 | + |
|
415 | + /** |
|
416 | + * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is. |
|
417 | + * |
|
418 | + * @param array $input The array to work on |
|
419 | + * @param int $case Either MB_CASE_UPPER or MB_CASE_LOWER (default) |
|
420 | + * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8 |
|
421 | + * @return array |
|
422 | + * @since 4.5.0 |
|
423 | + */ |
|
424 | + public static function mb_array_change_key_case($input, $case = MB_CASE_LOWER, $encoding = 'UTF-8') { |
|
425 | + return \OC_Helper::mb_array_change_key_case($input, $case, $encoding); |
|
426 | + } |
|
427 | + |
|
428 | + /** |
|
429 | + * replaces a copy of string delimited by the start and (optionally) length parameters with the string given in replacement. |
|
430 | + * |
|
431 | + * @param string $string The input string. Opposite to the PHP build-in function does not accept an array. |
|
432 | + * @param string $replacement The replacement string. |
|
433 | + * @param int $start If start is positive, the replacing will begin at the start'th offset into string. If start is negative, the replacing will begin at the start'th character from the end of string. |
|
434 | + * @param int $length Length of the part to be replaced |
|
435 | + * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8 |
|
436 | + * @return string |
|
437 | + * @since 4.5.0 |
|
438 | + * @deprecated 8.2.0 Use substr_replace() instead. |
|
439 | + */ |
|
440 | + public static function mb_substr_replace($string, $replacement, $start, $length = null, $encoding = 'UTF-8') { |
|
441 | + return substr_replace($string, $replacement, $start, $length); |
|
442 | + } |
|
443 | + |
|
444 | + /** |
|
445 | + * Replace all occurrences of the search string with the replacement string |
|
446 | + * |
|
447 | + * @param string $search The value being searched for, otherwise known as the needle. String. |
|
448 | + * @param string $replace The replacement string. |
|
449 | + * @param string $subject The string or array being searched and replaced on, otherwise known as the haystack. |
|
450 | + * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8 |
|
451 | + * @param int $count If passed, this will be set to the number of replacements performed. |
|
452 | + * @return string |
|
453 | + * @since 4.5.0 |
|
454 | + * @deprecated 8.2.0 Use str_replace() instead. |
|
455 | + */ |
|
456 | + public static function mb_str_replace($search, $replace, $subject, $encoding = 'UTF-8', &$count = null) { |
|
457 | + return str_replace($search, $replace, $subject, $count); |
|
458 | + } |
|
459 | + |
|
460 | + /** |
|
461 | + * performs a search in a nested array |
|
462 | + * |
|
463 | + * @param array $haystack the array to be searched |
|
464 | + * @param string $needle the search string |
|
465 | + * @param mixed $index optional, only search this key name |
|
466 | + * @return mixed the key of the matching field, otherwise false |
|
467 | + * @since 4.5.0 |
|
468 | + */ |
|
469 | + public static function recursiveArraySearch($haystack, $needle, $index = null) { |
|
470 | + return \OC_Helper::recursiveArraySearch($haystack, $needle, $index); |
|
471 | + } |
|
472 | + |
|
473 | + /** |
|
474 | + * calculates the maximum upload size respecting system settings, free space and user quota |
|
475 | + * |
|
476 | + * @param string $dir the current folder where the user currently operates |
|
477 | + * @param int $free the number of bytes free on the storage holding $dir, if not set this will be received from the storage directly |
|
478 | + * @return int number of bytes representing |
|
479 | + * @since 5.0.0 |
|
480 | + */ |
|
481 | + public static function maxUploadFilesize($dir, $free = null) { |
|
482 | + return \OC_Helper::maxUploadFilesize($dir, $free); |
|
483 | + } |
|
484 | + |
|
485 | + /** |
|
486 | + * Calculate free space left within user quota |
|
487 | + * @param string $dir the current folder where the user currently operates |
|
488 | + * @return int number of bytes representing |
|
489 | + * @since 7.0.0 |
|
490 | + */ |
|
491 | + public static function freeSpace($dir) { |
|
492 | + return \OC_Helper::freeSpace($dir); |
|
493 | + } |
|
494 | + |
|
495 | + /** |
|
496 | + * Calculate PHP upload limit |
|
497 | + * |
|
498 | + * @return int number of bytes representing |
|
499 | + * @since 7.0.0 |
|
500 | + */ |
|
501 | + public static function uploadLimit() { |
|
502 | + return \OC_Helper::uploadLimit(); |
|
503 | + } |
|
504 | + |
|
505 | + /** |
|
506 | + * Returns whether the given file name is valid |
|
507 | + * @param string $file file name to check |
|
508 | + * @return bool true if the file name is valid, false otherwise |
|
509 | + * @deprecated 8.1.0 use \OC\Files\View::verifyPath() |
|
510 | + * @since 7.0.0 |
|
511 | + * @suppress PhanDeprecatedFunction |
|
512 | + */ |
|
513 | + public static function isValidFileName($file) { |
|
514 | + return \OC_Util::isValidFileName($file); |
|
515 | + } |
|
516 | + |
|
517 | + /** |
|
518 | + * Compare two strings to provide a natural sort |
|
519 | + * @param string $a first string to compare |
|
520 | + * @param string $b second string to compare |
|
521 | + * @return int -1 if $b comes before $a, 1 if $a comes before $b |
|
522 | + * or 0 if the strings are identical |
|
523 | + * @since 7.0.0 |
|
524 | + */ |
|
525 | + public static function naturalSortCompare($a, $b) { |
|
526 | + return \OC\NaturalSort::getInstance()->compare($a, $b); |
|
527 | + } |
|
528 | + |
|
529 | + /** |
|
530 | + * check if a password is required for each public link |
|
531 | + * @return boolean |
|
532 | + * @since 7.0.0 |
|
533 | + */ |
|
534 | + public static function isPublicLinkPasswordRequired() { |
|
535 | + return \OC_Util::isPublicLinkPasswordRequired(); |
|
536 | + } |
|
537 | + |
|
538 | + /** |
|
539 | + * check if share API enforces a default expire date |
|
540 | + * @return boolean |
|
541 | + * @since 8.0.0 |
|
542 | + */ |
|
543 | + public static function isDefaultExpireDateEnforced() { |
|
544 | + return \OC_Util::isDefaultExpireDateEnforced(); |
|
545 | + } |
|
546 | + |
|
547 | + protected static $needUpgradeCache = null; |
|
548 | + |
|
549 | + /** |
|
550 | + * Checks whether the current version needs upgrade. |
|
551 | + * |
|
552 | + * @return bool true if upgrade is needed, false otherwise |
|
553 | + * @since 7.0.0 |
|
554 | + */ |
|
555 | + public static function needUpgrade() { |
|
556 | + if (!isset(self::$needUpgradeCache)) { |
|
557 | + self::$needUpgradeCache=\OC_Util::needUpgrade(\OC::$server->getSystemConfig()); |
|
558 | + } |
|
559 | + return self::$needUpgradeCache; |
|
560 | + } |
|
561 | 561 | } |
@@ -60,23 +60,23 @@ discard block |
||
60 | 60 | /** |
61 | 61 | * @deprecated 14.0.0 use \OCP\ILogger::DEBUG |
62 | 62 | */ |
63 | - const DEBUG=0; |
|
63 | + const DEBUG = 0; |
|
64 | 64 | /** |
65 | 65 | * @deprecated 14.0.0 use \OCP\ILogger::INFO |
66 | 66 | */ |
67 | - const INFO=1; |
|
67 | + const INFO = 1; |
|
68 | 68 | /** |
69 | 69 | * @deprecated 14.0.0 use \OCP\ILogger::WARN |
70 | 70 | */ |
71 | - const WARN=2; |
|
71 | + const WARN = 2; |
|
72 | 72 | /** |
73 | 73 | * @deprecated 14.0.0 use \OCP\ILogger::ERROR |
74 | 74 | */ |
75 | - const ERROR=3; |
|
75 | + const ERROR = 3; |
|
76 | 76 | /** |
77 | 77 | * @deprecated 14.0.0 use \OCP\ILogger::FATAL |
78 | 78 | */ |
79 | - const FATAL=4; |
|
79 | + const FATAL = 4; |
|
80 | 80 | |
81 | 81 | /** \OCP\Share\IManager */ |
82 | 82 | private static $shareManager; |
@@ -116,7 +116,7 @@ discard block |
||
116 | 116 | * @since 4.0.0 |
117 | 117 | * @deprecated 13.0.0 use log of \OCP\ILogger |
118 | 118 | */ |
119 | - public static function writeLog( $app, $message, $level ) { |
|
119 | + public static function writeLog($app, $message, $level) { |
|
120 | 120 | $context = ['app' => $app]; |
121 | 121 | \OC::$server->getLogger()->log($level, $message, $context); |
122 | 122 | } |
@@ -129,7 +129,7 @@ discard block |
||
129 | 129 | * @since ....0.0 - parameter $level was added in 7.0.0 |
130 | 130 | * @deprecated 8.2.0 use logException of \OCP\ILogger |
131 | 131 | */ |
132 | - public static function logException( $app, \Exception $ex, $level = ILogger::FATAL) { |
|
132 | + public static function logException($app, \Exception $ex, $level = ILogger::FATAL) { |
|
133 | 133 | \OC::$server->getLogger()->logException($ex, ['app' => $app]); |
134 | 134 | } |
135 | 135 | |
@@ -170,8 +170,8 @@ discard block |
||
170 | 170 | * @param string $file |
171 | 171 | * @since 4.0.0 |
172 | 172 | */ |
173 | - public static function addStyle( $application, $file = null ) { |
|
174 | - \OC_Util::addStyle( $application, $file ); |
|
173 | + public static function addStyle($application, $file = null) { |
|
174 | + \OC_Util::addStyle($application, $file); |
|
175 | 175 | } |
176 | 176 | |
177 | 177 | /** |
@@ -180,8 +180,8 @@ discard block |
||
180 | 180 | * @param string $file |
181 | 181 | * @since 4.0.0 |
182 | 182 | */ |
183 | - public static function addScript( $application, $file = null ) { |
|
184 | - \OC_Util::addScript( $application, $file ); |
|
183 | + public static function addScript($application, $file = null) { |
|
184 | + \OC_Util::addScript($application, $file); |
|
185 | 185 | } |
186 | 186 | |
187 | 187 | /** |
@@ -203,7 +203,7 @@ discard block |
||
203 | 203 | * @param string $text the text content for the element |
204 | 204 | * @since 4.0.0 |
205 | 205 | */ |
206 | - public static function addHeader($tag, $attributes, $text=null) { |
|
206 | + public static function addHeader($tag, $attributes, $text = null) { |
|
207 | 207 | \OC_Util::addHeader($tag, $attributes, $text); |
208 | 208 | } |
209 | 209 | |
@@ -216,7 +216,7 @@ discard block |
||
216 | 216 | * @return string the url |
217 | 217 | * @since 4.0.0 - parameter $args was added in 4.5.0 |
218 | 218 | */ |
219 | - public static function linkToAbsolute( $app, $file, $args = array() ) { |
|
219 | + public static function linkToAbsolute($app, $file, $args = array()) { |
|
220 | 220 | $urlGenerator = \OC::$server->getURLGenerator(); |
221 | 221 | return $urlGenerator->getAbsoluteURL( |
222 | 222 | $urlGenerator->linkTo($app, $file, $args) |
@@ -229,11 +229,11 @@ discard block |
||
229 | 229 | * @return string the url |
230 | 230 | * @since 4.0.0 |
231 | 231 | */ |
232 | - public static function linkToRemote( $service ) { |
|
232 | + public static function linkToRemote($service) { |
|
233 | 233 | $urlGenerator = \OC::$server->getURLGenerator(); |
234 | - $remoteBase = $urlGenerator->linkTo('', 'remote.php') . '/' . $service; |
|
234 | + $remoteBase = $urlGenerator->linkTo('', 'remote.php').'/'.$service; |
|
235 | 235 | return $urlGenerator->getAbsoluteURL( |
236 | - $remoteBase . (($service[strlen($service) - 1] != '/') ? '/' : '') |
|
236 | + $remoteBase.(($service[strlen($service) - 1] != '/') ? '/' : '') |
|
237 | 237 | ); |
238 | 238 | } |
239 | 239 | |
@@ -361,7 +361,7 @@ discard block |
||
361 | 361 | * @since 4.5.0 |
362 | 362 | */ |
363 | 363 | public static function callRegister() { |
364 | - if(self::$token === '') { |
|
364 | + if (self::$token === '') { |
|
365 | 365 | self::$token = \OC::$server->getCsrfTokenManager()->getToken()->getEncryptedValue(); |
366 | 366 | } |
367 | 367 | return self::$token; |
@@ -373,7 +373,7 @@ discard block |
||
373 | 373 | * @deprecated 9.0.0 Use annotations based on the app framework. |
374 | 374 | */ |
375 | 375 | public static function callCheck() { |
376 | - if(!\OC::$server->getRequest()->passesStrictCookieCheck()) { |
|
376 | + if (!\OC::$server->getRequest()->passesStrictCookieCheck()) { |
|
377 | 377 | header('Location: '.\OC::$WEBROOT); |
378 | 378 | exit(); |
379 | 379 | } |
@@ -554,7 +554,7 @@ discard block |
||
554 | 554 | */ |
555 | 555 | public static function needUpgrade() { |
556 | 556 | if (!isset(self::$needUpgradeCache)) { |
557 | - self::$needUpgradeCache=\OC_Util::needUpgrade(\OC::$server->getSystemConfig()); |
|
557 | + self::$needUpgradeCache = \OC_Util::needUpgrade(\OC::$server->getSystemConfig()); |
|
558 | 558 | } |
559 | 559 | return self::$needUpgradeCache; |
560 | 560 | } |
@@ -36,134 +36,134 @@ |
||
36 | 36 | * https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#3-psrlogloggerinterface |
37 | 37 | */ |
38 | 38 | interface ILogger { |
39 | - /** |
|
40 | - * @since 14.0.0 |
|
41 | - */ |
|
42 | - const DEBUG=0; |
|
43 | - /** |
|
44 | - * @since 14.0.0 |
|
45 | - */ |
|
46 | - const INFO=1; |
|
47 | - /** |
|
48 | - * @since 14.0.0 |
|
49 | - */ |
|
50 | - const WARN=2; |
|
51 | - /** |
|
52 | - * @since 14.0.0 |
|
53 | - */ |
|
54 | - const ERROR=3; |
|
55 | - /** |
|
56 | - * @since 14.0.0 |
|
57 | - */ |
|
58 | - const FATAL=4; |
|
39 | + /** |
|
40 | + * @since 14.0.0 |
|
41 | + */ |
|
42 | + const DEBUG=0; |
|
43 | + /** |
|
44 | + * @since 14.0.0 |
|
45 | + */ |
|
46 | + const INFO=1; |
|
47 | + /** |
|
48 | + * @since 14.0.0 |
|
49 | + */ |
|
50 | + const WARN=2; |
|
51 | + /** |
|
52 | + * @since 14.0.0 |
|
53 | + */ |
|
54 | + const ERROR=3; |
|
55 | + /** |
|
56 | + * @since 14.0.0 |
|
57 | + */ |
|
58 | + const FATAL=4; |
|
59 | 59 | |
60 | - /** |
|
61 | - * System is unusable. |
|
62 | - * |
|
63 | - * @param string $message |
|
64 | - * @param array $context |
|
65 | - * @return null |
|
66 | - * @since 7.0.0 |
|
67 | - */ |
|
68 | - public function emergency(string $message, array $context = []); |
|
60 | + /** |
|
61 | + * System is unusable. |
|
62 | + * |
|
63 | + * @param string $message |
|
64 | + * @param array $context |
|
65 | + * @return null |
|
66 | + * @since 7.0.0 |
|
67 | + */ |
|
68 | + public function emergency(string $message, array $context = []); |
|
69 | 69 | |
70 | - /** |
|
71 | - * Action must be taken immediately. |
|
72 | - * |
|
73 | - * @param string $message |
|
74 | - * @param array $context |
|
75 | - * @return null |
|
76 | - * @since 7.0.0 |
|
77 | - */ |
|
78 | - public function alert(string $message, array $context = []); |
|
70 | + /** |
|
71 | + * Action must be taken immediately. |
|
72 | + * |
|
73 | + * @param string $message |
|
74 | + * @param array $context |
|
75 | + * @return null |
|
76 | + * @since 7.0.0 |
|
77 | + */ |
|
78 | + public function alert(string $message, array $context = []); |
|
79 | 79 | |
80 | - /** |
|
81 | - * Critical conditions. |
|
82 | - * |
|
83 | - * @param string $message |
|
84 | - * @param array $context |
|
85 | - * @return null |
|
86 | - * @since 7.0.0 |
|
87 | - */ |
|
88 | - public function critical(string $message, array $context = []); |
|
80 | + /** |
|
81 | + * Critical conditions. |
|
82 | + * |
|
83 | + * @param string $message |
|
84 | + * @param array $context |
|
85 | + * @return null |
|
86 | + * @since 7.0.0 |
|
87 | + */ |
|
88 | + public function critical(string $message, array $context = []); |
|
89 | 89 | |
90 | - /** |
|
91 | - * Runtime errors that do not require immediate action but should typically |
|
92 | - * be logged and monitored. |
|
93 | - * |
|
94 | - * @param string $message |
|
95 | - * @param array $context |
|
96 | - * @return null |
|
97 | - * @since 7.0.0 |
|
98 | - */ |
|
99 | - public function error(string $message, array $context = []); |
|
90 | + /** |
|
91 | + * Runtime errors that do not require immediate action but should typically |
|
92 | + * be logged and monitored. |
|
93 | + * |
|
94 | + * @param string $message |
|
95 | + * @param array $context |
|
96 | + * @return null |
|
97 | + * @since 7.0.0 |
|
98 | + */ |
|
99 | + public function error(string $message, array $context = []); |
|
100 | 100 | |
101 | - /** |
|
102 | - * Exceptional occurrences that are not errors. |
|
103 | - * |
|
104 | - * @param string $message |
|
105 | - * @param array $context |
|
106 | - * @return null |
|
107 | - * @since 7.0.0 |
|
108 | - */ |
|
109 | - public function warning(string $message, array $context = []); |
|
101 | + /** |
|
102 | + * Exceptional occurrences that are not errors. |
|
103 | + * |
|
104 | + * @param string $message |
|
105 | + * @param array $context |
|
106 | + * @return null |
|
107 | + * @since 7.0.0 |
|
108 | + */ |
|
109 | + public function warning(string $message, array $context = []); |
|
110 | 110 | |
111 | - /** |
|
112 | - * Normal but significant events. |
|
113 | - * |
|
114 | - * @param string $message |
|
115 | - * @param array $context |
|
116 | - * @return null |
|
117 | - * @since 7.0.0 |
|
118 | - */ |
|
119 | - public function notice(string $message, array $context = []); |
|
111 | + /** |
|
112 | + * Normal but significant events. |
|
113 | + * |
|
114 | + * @param string $message |
|
115 | + * @param array $context |
|
116 | + * @return null |
|
117 | + * @since 7.0.0 |
|
118 | + */ |
|
119 | + public function notice(string $message, array $context = []); |
|
120 | 120 | |
121 | - /** |
|
122 | - * Interesting events. |
|
123 | - * |
|
124 | - * @param string $message |
|
125 | - * @param array $context |
|
126 | - * @return null |
|
127 | - * @since 7.0.0 |
|
128 | - */ |
|
129 | - public function info(string $message, array $context = []); |
|
121 | + /** |
|
122 | + * Interesting events. |
|
123 | + * |
|
124 | + * @param string $message |
|
125 | + * @param array $context |
|
126 | + * @return null |
|
127 | + * @since 7.0.0 |
|
128 | + */ |
|
129 | + public function info(string $message, array $context = []); |
|
130 | 130 | |
131 | - /** |
|
132 | - * Detailed debug information. |
|
133 | - * |
|
134 | - * @param string $message |
|
135 | - * @param array $context |
|
136 | - * @return null |
|
137 | - * @since 7.0.0 |
|
138 | - */ |
|
139 | - public function debug(string $message, array $context = []); |
|
131 | + /** |
|
132 | + * Detailed debug information. |
|
133 | + * |
|
134 | + * @param string $message |
|
135 | + * @param array $context |
|
136 | + * @return null |
|
137 | + * @since 7.0.0 |
|
138 | + */ |
|
139 | + public function debug(string $message, array $context = []); |
|
140 | 140 | |
141 | - /** |
|
142 | - * Logs with an arbitrary level. |
|
143 | - * |
|
144 | - * @param int $level |
|
145 | - * @param string $message |
|
146 | - * @param array $context |
|
147 | - * @return mixed |
|
148 | - * @since 7.0.0 |
|
149 | - */ |
|
150 | - public function log(int $level, string $message, array $context = []); |
|
141 | + /** |
|
142 | + * Logs with an arbitrary level. |
|
143 | + * |
|
144 | + * @param int $level |
|
145 | + * @param string $message |
|
146 | + * @param array $context |
|
147 | + * @return mixed |
|
148 | + * @since 7.0.0 |
|
149 | + */ |
|
150 | + public function log(int $level, string $message, array $context = []); |
|
151 | 151 | |
152 | - /** |
|
153 | - * Logs an exception very detailed |
|
154 | - * An additional message can we written to the log by adding it to the |
|
155 | - * context. |
|
156 | - * |
|
157 | - * <code> |
|
158 | - * $logger->logException($ex, [ |
|
159 | - * 'message' => 'Exception during background job execution' |
|
160 | - * ]); |
|
161 | - * </code> |
|
162 | - * |
|
163 | - * @param \Exception|\Throwable $exception |
|
164 | - * @param array $context |
|
165 | - * @return void |
|
166 | - * @since 8.2.0 |
|
167 | - */ |
|
168 | - public function logException(\Throwable $exception, array $context = []); |
|
152 | + /** |
|
153 | + * Logs an exception very detailed |
|
154 | + * An additional message can we written to the log by adding it to the |
|
155 | + * context. |
|
156 | + * |
|
157 | + * <code> |
|
158 | + * $logger->logException($ex, [ |
|
159 | + * 'message' => 'Exception during background job execution' |
|
160 | + * ]); |
|
161 | + * </code> |
|
162 | + * |
|
163 | + * @param \Exception|\Throwable $exception |
|
164 | + * @param array $context |
|
165 | + * @return void |
|
166 | + * @since 8.2.0 |
|
167 | + */ |
|
168 | + public function logException(\Throwable $exception, array $context = []); |
|
169 | 169 | } |
@@ -39,23 +39,23 @@ |
||
39 | 39 | /** |
40 | 40 | * @since 14.0.0 |
41 | 41 | */ |
42 | - const DEBUG=0; |
|
42 | + const DEBUG = 0; |
|
43 | 43 | /** |
44 | 44 | * @since 14.0.0 |
45 | 45 | */ |
46 | - const INFO=1; |
|
46 | + const INFO = 1; |
|
47 | 47 | /** |
48 | 48 | * @since 14.0.0 |
49 | 49 | */ |
50 | - const WARN=2; |
|
50 | + const WARN = 2; |
|
51 | 51 | /** |
52 | 52 | * @since 14.0.0 |
53 | 53 | */ |
54 | - const ERROR=3; |
|
54 | + const ERROR = 3; |
|
55 | 55 | /** |
56 | 56 | * @since 14.0.0 |
57 | 57 | */ |
58 | - const FATAL=4; |
|
58 | + const FATAL = 4; |
|
59 | 59 | |
60 | 60 | /** |
61 | 61 | * System is unusable. |
@@ -32,30 +32,30 @@ |
||
32 | 32 | |
33 | 33 | $lastConfirm = (int) \OC::$server->getSession()->get('last-password-confirm'); |
34 | 34 | if ($lastConfirm < (time() - 30 * 60 + 15)) { // allow 15 seconds delay |
35 | - $l = \OC::$server->getL10N('core'); |
|
36 | - OC_JSON::error(array( 'data' => array( 'message' => $l->t('Password confirmation is required')))); |
|
37 | - exit(); |
|
35 | + $l = \OC::$server->getL10N('core'); |
|
36 | + OC_JSON::error(array( 'data' => array( 'message' => $l->t('Password confirmation is required')))); |
|
37 | + exit(); |
|
38 | 38 | } |
39 | 39 | |
40 | 40 | $groups = isset($_POST['groups']) ? (array)$_POST['groups'] : []; |
41 | 41 | $appIds = isset($_POST['appIds']) ? (array)$_POST['appIds'] : []; |
42 | 42 | |
43 | 43 | try { |
44 | - $updateRequired = false; |
|
45 | - foreach($appIds as $appId) { |
|
46 | - $app = new OC_App(); |
|
47 | - $appId = OC_App::cleanAppId($appId); |
|
48 | - $app->enable($appId, $groups); |
|
49 | - if(\OC_App::shouldUpgrade($appId)) { |
|
50 | - $updateRequired = true; |
|
51 | - } |
|
52 | - } |
|
44 | + $updateRequired = false; |
|
45 | + foreach($appIds as $appId) { |
|
46 | + $app = new OC_App(); |
|
47 | + $appId = OC_App::cleanAppId($appId); |
|
48 | + $app->enable($appId, $groups); |
|
49 | + if(\OC_App::shouldUpgrade($appId)) { |
|
50 | + $updateRequired = true; |
|
51 | + } |
|
52 | + } |
|
53 | 53 | |
54 | - OC_JSON::success(['data' => ['update_required' => $updateRequired]]); |
|
54 | + OC_JSON::success(['data' => ['update_required' => $updateRequired]]); |
|
55 | 55 | } catch (Exception $e) { |
56 | - \OC::$server->getLogger()->logException($e, [ |
|
57 | - 'level' => ILogger::DEBUG, |
|
58 | - 'app' => 'core', |
|
59 | - ]); |
|
60 | - OC_JSON::error(array("data" => array("message" => $e->getMessage()) )); |
|
56 | + \OC::$server->getLogger()->logException($e, [ |
|
57 | + 'level' => ILogger::DEBUG, |
|
58 | + 'app' => 'core', |
|
59 | + ]); |
|
60 | + OC_JSON::error(array("data" => array("message" => $e->getMessage()) )); |
|
61 | 61 | } |
@@ -33,20 +33,20 @@ discard block |
||
33 | 33 | $lastConfirm = (int) \OC::$server->getSession()->get('last-password-confirm'); |
34 | 34 | if ($lastConfirm < (time() - 30 * 60 + 15)) { // allow 15 seconds delay |
35 | 35 | $l = \OC::$server->getL10N('core'); |
36 | - OC_JSON::error(array( 'data' => array( 'message' => $l->t('Password confirmation is required')))); |
|
36 | + OC_JSON::error(array('data' => array('message' => $l->t('Password confirmation is required')))); |
|
37 | 37 | exit(); |
38 | 38 | } |
39 | 39 | |
40 | -$groups = isset($_POST['groups']) ? (array)$_POST['groups'] : []; |
|
41 | -$appIds = isset($_POST['appIds']) ? (array)$_POST['appIds'] : []; |
|
40 | +$groups = isset($_POST['groups']) ? (array) $_POST['groups'] : []; |
|
41 | +$appIds = isset($_POST['appIds']) ? (array) $_POST['appIds'] : []; |
|
42 | 42 | |
43 | 43 | try { |
44 | 44 | $updateRequired = false; |
45 | - foreach($appIds as $appId) { |
|
45 | + foreach ($appIds as $appId) { |
|
46 | 46 | $app = new OC_App(); |
47 | 47 | $appId = OC_App::cleanAppId($appId); |
48 | 48 | $app->enable($appId, $groups); |
49 | - if(\OC_App::shouldUpgrade($appId)) { |
|
49 | + if (\OC_App::shouldUpgrade($appId)) { |
|
50 | 50 | $updateRequired = true; |
51 | 51 | } |
52 | 52 | } |
@@ -57,5 +57,5 @@ discard block |
||
57 | 57 | 'level' => ILogger::DEBUG, |
58 | 58 | 'app' => 'core', |
59 | 59 | ]); |
60 | - OC_JSON::error(array("data" => array("message" => $e->getMessage()) )); |
|
60 | + OC_JSON::error(array("data" => array("message" => $e->getMessage()))); |
|
61 | 61 | } |