source: documentation/trunk/packages/dokuwiki-2011-05-25a/lib/plugins/plugin/classes/ap_download.class.php@ 25027

Last change on this file since 25027 was 25027, checked in by jmt12, 12 years ago

Adding the packages directory, and within it a configured version of dokuwiki all ready to run

File size: 9.8 KB
Line 
1<?php
2class ap_download extends ap_manage {
3
4 var $overwrite = true;
5
6 /**
7 * Initiate the plugin download
8 */
9 function process() {
10 global $lang;
11
12 $plugin_url = $_REQUEST['url'];
13 $this->download($plugin_url, $this->overwrite);
14 return '';
15 }
16
17 /**
18 * Print results of the download
19 */
20 function html() {
21 parent::html();
22
23 ptln('<div class="pm_info">');
24 ptln('<h2>'.$this->lang['downloading'].'</h2>');
25
26 if ($this->manager->error) {
27 ptln('<div class="error">'.str_replace("\n","<br />",$this->manager->error).'</div>');
28 } else if (count($this->downloaded) == 1) {
29 ptln('<p>'.sprintf($this->lang['downloaded'],$this->downloaded[0]).'</p>');
30 } else if (count($this->downloaded)) { // more than one plugin in the download
31 ptln('<p>'.$this->lang['downloads'].'</p>');
32 ptln('<ul>');
33 foreach ($this->downloaded as $plugin) {
34 ptln('<li><div class="li">'.$plugin.'</div></li>',2);
35 }
36 ptln('</ul>');
37 } else { // none found in download
38 ptln('<p>'.$this->lang['download_none'].'</p>');
39 }
40 ptln('</div>');
41 }
42
43 /**
44 * Process the downloaded file
45 */
46 function download($url, $overwrite=false) {
47 global $lang;
48 // check the url
49 $matches = array();
50 if (!preg_match("/[^\/]*$/", $url, $matches) || !$matches[0]) {
51 $this->manager->error = $this->lang['error_badurl']."\n";
52 return false;
53 }
54
55 $file = $matches[0];
56
57 if (!($tmp = io_mktmpdir())) {
58 $this->manager->error = $this->lang['error_dircreate']."\n";
59 return false;
60 }
61
62 if (!$file = io_download($url, "$tmp/", true, $file)) {
63 $this->manager->error = sprintf($this->lang['error_download'],$url)."\n";
64 }
65
66 if (!$this->manager->error && !$this->decompress("$tmp/$file", $tmp)) {
67 $this->manager->error = sprintf($this->lang['error_decompress'],$file)."\n";
68 }
69
70 // search $tmp for the folder(s) that has been created
71 // move the folder(s) to lib/plugins/
72 if (!$this->manager->error) {
73 $result = array('old'=>array(), 'new'=>array());
74 if($this->find_folders($result,$tmp)){
75 // choose correct result array
76 if(count($result['new'])){
77 $install = $result['new'];
78 }else{
79 $install = $result['old'];
80 }
81
82 // now install all found items
83 foreach($install as $item){
84 // where to install?
85 if($item['type'] == 'template'){
86 $target = DOKU_INC.'lib/tpl/'.$item['base'];
87 }else{
88 $target = DOKU_INC.'lib/plugins/'.$item['base'];
89 }
90
91 // check to make sure we aren't overwriting anything
92 if (!$overwrite && @file_exists($target)) {
93 // remember our settings, ask the user to confirm overwrite, FIXME
94 continue;
95 }
96
97 $instruction = @file_exists($target) ? 'update' : 'install';
98
99 // copy action
100 if ($this->dircopy($item['tmp'], $target)) {
101 $this->downloaded[] = $item['base'];
102 $this->plugin_writelog($target, $instruction, array($url));
103 } else {
104 $this->manager->error .= sprintf($this->lang['error_copy']."\n", $item['base']);
105 }
106 }
107
108 } else {
109 $this->manager->error = $this->lang['error']."\n";
110 }
111 }
112
113 // cleanup
114 if ($tmp) $this->dir_delete($tmp);
115
116 if (!$this->manager->error) {
117 msg(sprintf($this->lang['packageinstalled'], count($this->downloaded), (count($this->downloaded) != 1?'s':''), join(',',$this->downloaded)),1);
118 $this->refresh();
119 return true;
120 }
121
122 return false;
123 }
124
125 /**
126 * Find out what was in the extracted directory
127 *
128 * Correct folders are searched recursively using the "*.info.txt" configs
129 * as indicator for a root folder. When such a file is found, it's base
130 * setting is used (when set). All folders found by this method are stored
131 * in the 'new' key of the $result array.
132 *
133 * For backwards compatibility all found top level folders are stored as
134 * in the 'old' key of the $result array.
135 *
136 * When no items are found in 'new' the copy mechanism should fall back
137 * the 'old' list.
138 *
139 * @author Andreas Gohr <[email protected]>
140 * @param arrayref $result - results are stored here
141 * @param string $base - the temp directory where the package was unpacked to
142 * @param string $dir - a subdirectory. do not set. used by recursion
143 * @return bool - false on error
144 */
145 function find_folders(&$result,$base,$dir=''){
146 $dh = @opendir("$base/$dir");
147 if(!$dh) return false;
148 while (false !== ($f = readdir($dh))) {
149 if ($f == '.' || $f == '..' || $f == 'tmp') continue;
150
151 if(!is_dir("$base/$dir/$f")){
152 // it's a file -> check for config
153 if($f == 'plugin.info.txt'){
154 $info = array();
155 $info['type'] = 'plugin';
156 $info['tmp'] = "$base/$dir";
157 $conf = confToHash("$base/$dir/$f");
158 $info['base'] = basename($conf['base']);
159 if(!$info['base']) $info['base'] = basename("$base/$dir");
160 $result['new'][] = $info;
161 }elseif($f == 'template.info.txt'){
162 $info = array();
163 $info['type'] = 'template';
164 $info['tmp'] = "$base/$dir";
165 $conf = confToHash("$base/$dir/$f");
166 $info['base'] = basename($conf['base']);
167 if(!$info['base']) $info['base'] = basename("$base/$dir");
168 $result['new'][] = $info;
169 }
170 }else{
171 // it's a directory -> add to dir list for old method, then recurse
172 if(!$dir){
173 $info = array();
174 $info['type'] = 'plugin';
175 $info['tmp'] = "$base/$dir/$f";
176 $info['base'] = $f;
177 $result['old'][] = $info;
178 }
179 $this->find_folders($result,$base,"$dir/$f");
180 }
181 }
182 closedir($dh);
183 return true;
184 }
185
186
187 /**
188 * Decompress a given file to the given target directory
189 *
190 * Determines the compression type from the file extension
191 */
192 function decompress($file, $target) {
193 global $conf;
194
195 // decompression library doesn't like target folders ending in "/"
196 if (substr($target, -1) == "/") $target = substr($target, 0, -1);
197
198 $ext = $this->guess_archive($file);
199 if (in_array($ext, array('tar','bz','gz'))) {
200 switch($ext){
201 case 'bz':
202 $compress_type = TarLib::COMPRESS_BZIP;
203 break;
204 case 'gz':
205 $compress_type = TarLib::COMPRESS_GZIP;
206 break;
207 default:
208 $compress_type = TarLib::COMPRESS_NONE;
209 }
210
211 $tar = new TarLib($file, $compress_type);
212 if($tar->_initerror < 0){
213 if($conf['allowdebug']){
214 msg('TarLib Error: '.$tar->TarErrorStr($tar->_initerror),-1);
215 }
216 return false;
217 }
218 $ok = $tar->Extract(TarLib::FULL_ARCHIVE, $target, '', 0777);
219
220 if($ok<1){
221 if($conf['allowdebug']){
222 msg('TarLib Error: '.$tar->TarErrorStr($ok),-1);
223 }
224 return false;
225 }
226 return true;
227 } else if ($ext == 'zip') {
228
229 $zip = new ZipLib();
230 $ok = $zip->Extract($file, $target);
231
232 // FIXME sort something out for handling zip error messages meaningfully
233 return ($ok==-1?false:true);
234
235 }
236
237 // unsupported file type
238 return false;
239 }
240
241 /**
242 * Determine the archive type of the given file
243 *
244 * Reads the first magic bytes of the given file for content type guessing,
245 * if neither bz, gz or zip are recognized, tar is assumed.
246 *
247 * @author Andreas Gohr <[email protected]>
248 * @returns false if the file can't be read, otherwise an "extension"
249 */
250 function guess_archive($file){
251 $fh = fopen($file,'rb');
252 if(!$fh) return false;
253 $magic = fread($fh,5);
254 fclose($fh);
255
256 if(strpos($magic,"\x42\x5a") === 0) return 'bz';
257 if(strpos($magic,"\x1f\x8b") === 0) return 'gz';
258 if(strpos($magic,"\x50\x4b\x03\x04") === 0) return 'zip';
259 return 'tar';
260 }
261
262 /**
263 * Copy with recursive sub-directory support
264 */
265 function dircopy($src, $dst) {
266 global $conf;
267
268 if (is_dir($src)) {
269 if (!$dh = @opendir($src)) return false;
270
271 if ($ok = io_mkdir_p($dst)) {
272 while ($ok && (false !== ($f = readdir($dh)))) {
273 if ($f == '..' || $f == '.') continue;
274 $ok = $this->dircopy("$src/$f", "$dst/$f");
275 }
276 }
277
278 closedir($dh);
279 return $ok;
280
281 } else {
282 $exists = @file_exists($dst);
283
284 if (!@copy($src,$dst)) return false;
285 if (!$exists && !empty($conf['fperm'])) chmod($dst, $conf['fperm']);
286 @touch($dst,filemtime($src));
287 }
288
289 return true;
290 }
291
292
293}
294
Note: See TracBrowser for help on using the repository browser.