2 class ap_download
extends ap_manage
{
4 var $overwrite = false;
7 * Initiate the plugin download
12 $plugin_url = $_REQUEST['url'];
13 $this->download($plugin_url, $this->overwrite
);
18 * Print results of the download
23 ptln('<div class="pm_info">');
24 ptln('<h2>'.$this->lang
['downloading'].'</h2>');
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>');
33 foreach ($this->downloaded
as $plugin) {
34 ptln('<li><div class="li">'.$plugin.'</div></li>',2);
37 } else { // none found in download
38 ptln('<p>'.$this->lang
['download_none'].'</p>');
44 * Process the downloaded file
46 function download($url, $overwrite=false) {
50 if (!preg_match("/[^\/]*$/", $url, $matches) ||
!$matches[0]) {
51 $this->manager
->error
= $this->lang
['error_badurl']."\n";
57 if (!($tmp = io_mktmpdir())) {
58 $this->manager
->error
= $this->lang
['error_dircreate']."\n";
62 if (!$file = io_download($url, "$tmp/", true, $file)) {
63 $this->manager
->error
= sprintf($this->lang
['error_download'],$url)."\n";
66 if (!$this->manager
->error
&& !$this->decompress("$tmp/$file", $tmp)) {
67 $this->manager
->error
= sprintf($this->lang
['error_decompress'],$file)."\n";
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'];
79 $install = $result['old'];
82 // now install all found items
83 foreach($install as $item){
85 if($item['type'] == 'template'){
86 $target = DOKU_INC
.'lib/tpl/'.$item['base'];
88 $target = DOKU_INC
.'lib/plugins/'.$item['base'];
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
97 $instruction = @file_exists
($target) ?
'update' : 'install';
100 if ($this->dircopy($item['tmp'], $target)) {
101 $this->downloaded
[] = $item['base'];
102 $this->plugin_writelog($target, $instruction, array($url));
104 $this->manager
->error
.= sprintf($this->lang
['error_copy']."\n", $item['base']);
109 $this->manager
->error
= $this->lang
['error']."\n";
114 if ($tmp) $this->dir_delete($tmp);
116 if (!$this->manager
->error
) {
117 msg('Plugin package ('.count($this->downloaded
).' plugin'.(count($this->downloaded
) != 1?
's':'').': '.join(',',$this->downloaded
).') successfully installed.',1);
126 * Find out what was in the extracted directory
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.
133 * For backwards compatibility all found top level folders are stored as
134 * in the 'old' key of the $result array.
136 * When no items are found in 'new' the copy mechanism should fall back
139 * @author Andreas Gohr <andi@splitbrain.org>
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
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;
151 if(!is_dir("$base/$dir/$f")){
152 // it's a file -> check for config
153 if($f == 'plugin.info.txt'){
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'){
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;
171 // it's a directory -> add to dir list for old method, then recurse
174 $info['type'] = 'plugin';
175 $info['tmp'] = "$base/$dir/$f";
177 $result['old'][] = $info;
179 $this->find_folders($result,$base,"$dir/$f");
188 * Decompress a given file to the given target directory
190 * Determines the compression type from the file extension
192 function decompress($file, $target) {
195 // decompression library doesn't like target folders ending in "/"
196 if (substr($target, -1) == "/") $target = substr($target, 0, -1);
198 $ext = $this->guess_archive($file);
199 if (in_array($ext, array('tar','bz','gz'))) {
200 require_once(DOKU_INC
."inc/TarLib.class.php");
204 $compress_type = COMPRESS_BZIP
;
207 $compress_type = COMPRESS_GZIP
;
210 $compress_type = COMPRESS_NONE
;
213 $tar = new TarLib($file, $compress_type);
214 if($tar->_initerror
< 0){
215 if($conf['allowdebug']){
216 msg('TarLib Error: '.$tar->TarErrorStr($tar->_initerror
),-1);
220 $ok = $tar->Extract(FULL_ARCHIVE
, $target, '', 0777);
223 if($conf['allowdebug']){
224 msg('TarLib Error: '.$tar->TarErrorStr($ok),-1);
229 } else if ($ext == 'zip') {
230 require_once(DOKU_INC
."inc/ZipLib.class.php");
233 $ok = $zip->Extract($file, $target);
235 // FIXME sort something out for handling zip error messages meaningfully
236 return ($ok==-1?
false:true);
240 // unsupported file type
245 * Determine the archive type of the given file
247 * Reads the first magic bytes of the given file for content type guessing,
248 * if neither bz, gz or zip are recognized, tar is assumed.
250 * @author Andreas Gohr <andi@splitbrain.org>
251 * @returns false if the file can't be read, otherwise an "extension"
253 function guess_archive($file){
254 $fh = fopen($file,'rb');
255 if(!$fh) return false;
256 $magic = fread($fh,5);
259 if(strpos($magic,"\x42\x5a") === 0) return 'bz';
260 if(strpos($magic,"\x1f\x8b") === 0) return 'gz';
261 if(strpos($magic,"\x50\x4b\x03\x04") === 0) return 'zip';
266 * Copy with recursive sub-directory support
268 function dircopy($src, $dst) {
272 if (!$dh = @opendir
($src)) return false;
274 if ($ok = io_mkdir_p($dst)) {
275 while ($ok && (false !== ($f = readdir($dh)))) {
276 if ($f == '..' ||
$f == '.') continue;
277 $ok = $this->dircopy("$src/$f", "$dst/$f");
285 $exists = @file_exists
($dst);
287 if (!@copy
($src,$dst)) return false;
288 if (!$exists && !empty($conf['fperm'])) chmod($dst, $conf['fperm']);
289 @touch
($dst,filemtime($src));