]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/FileInfo.php
Normalize header
[SourceForge/phpwiki.git] / lib / plugin / FileInfo.php
1 <?php // -*-php-*-
2 rcs_id('$Id$');
3 /*
4  * Copyright 2005,2007 $ThePhpWikiProgrammingTeam
5  * Copyright 2008-2009 Marc-Etienne Vargenau, Alcatel-Lucent
6  * 
7  * This file is part of PhpWiki.
8  *
9  * PhpWiki is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * PhpWiki is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with PhpWiki; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 /**
25  * This plugin displays the version, date, size, perms of an uploaded file.
26  * Only files relative and below to the uploads path can be handled.
27  *
28  * Usage:
29  *   <?plugin FileInfo file=Upload:setup.exe display=version,date ?>
30  *   <?plugin FileInfo file=Upload:setup.exe display=name,version,date 
31  *                     format="%s (version: %s, date: %s)" ?>
32  *
33  * @author: ReiniUrban
34  */
35
36 class WikiPlugin_FileInfo
37 extends WikiPlugin
38 {
39     function getName () {
40         return _("FileInfo");
41     }
42
43     function getDescription () {
44         return _("Display file information like version, size, date... of uploaded files.");
45     }
46
47     function getVersion() {
48         return preg_replace("/[Revision: $]/", '',
49                             "\$Revision$");
50     }
51
52     function getDefaultArguments() {
53         return array(
54                      'file'      => false, // relative path from PHPWIKI_DIR. (required)
55                      'display'   => false, // version,phonysize,size,date,mtime,owner,name,path,dirname,link.  (required)
56                      'format'    => false, // printf format string with %s only, all display modes 
57                      'quiet'     => false  // print no error if file not found
58                                            // from above vars return strings (optional)
59                     );
60     }
61
62     function run($dbi, $argstr, &$request, $basepage) {
63         $args = $this->getArgs($argstr, $request);
64         extract($args);
65         if (!$file)
66             return $this->error(sprintf(_("A required argument '%s' is missing."), 'file'));
67         if (!$display)
68             return $this->error(sprintf(_("A required argument '%s' is missing."), 'display'));
69         if (string_starts_with($file, "Upload:")) {
70             $file = preg_replace("/^Upload:(.*)$/", getUploadFilePath()."\\1", $file);
71             $is_Upload = 1;
72         }
73         $dir = getcwd();
74         if (defined('PHPWIKI_DIR')) {
75             chdir(PHPWIKI_DIR);
76         }
77         if (!file_exists($file)) {
78             if ($quiet) {
79                 return HTML::raw('');
80             } else {
81                 return $this->error(sprintf(_("File '%s' not found."), $file));
82             }
83         }
84         // sanify $file name
85         $realfile = realpath($file);
86         // Hmm, allow ADMIN to check a local file? Only if its locked
87         if (string_starts_with($realfile, realpath(getUploadDataPath()))) {
88             $isuploaded = 1;
89         } else {
90             $page = $dbi->getPage($basepage);
91             $user = $request->getUser();
92             if ($page->getOwner() != ADMIN_USER or !$page->get('locked')) {
93                 // For convenience we warn the admin
94                 if ($quiet and $user->isAdmin())
95                     return HTML::span(array('title' => _("Output suppressed. FileInfoPlugin with local files require a locked page.")),
96                                       HTML::em(_("page not locked")));
97                 else
98                     return $this->error("Invalid path \"$file\". Only ADMIN can allow local paths, and the page must be locked.");
99             }
100         }
101         $s = array();
102         $modes = explode(",", $display);
103         foreach ($modes as $mode) {
104             switch ($mode) {
105             case 'version':  $s[] = $this->exeversion($file); break;
106             case 'size':     $s[] = filesize($file); break;
107             case 'phonysize':$s[] = $this->phonysize(filesize($file)); break;
108             case 'date':     $s[] = strftime("%x %X", filemtime($file)); break;
109             case 'mtime':    $s[] = filemtime($file); break;
110             case 'owner':    $o = posix_getpwuid(fileowner($file)); $s[] = $o['name']; break;
111             case 'group':    $o = posix_getgrgid(filegroup($file)); $s[] = $o['name']; break;
112             case 'name':     $s[] = basename($file); break;
113             case 'path':     $s[] = $file; break;
114             case 'dirname':  $s[] = dirname($file); break;
115             case 'magic':    $s[] = $this->magic($file); break;
116             case 'mime-typ': $s[] = $this->mime_type($file); break;
117             case 'link':    
118                 if ($is_Upload) {
119                     $s[] = " [".$args['file'] . "]"; 
120                 } elseif ($isuploaded) {
121                     // will fail with user uploads
122                     $s[] = " [Upload:".basename($file)."]"; 
123                 } else {
124                     $s[] = " [".basename($file)."] "; 
125                 }
126                 break;
127             default:
128                 if (!$quiet) {
129                     return $this->error(sprintf(_("Unsupported argument: %s=%s"), 'display', $mode)); 
130                 } else {
131                     return HTML::raw('');
132                 }
133                 break;
134             }
135         }
136         chdir($dir);
137         if (!$format) {
138             $format = '';
139             foreach ($s as $x) { $format .= " %s"; }
140         }
141         array_unshift($s, $format);
142         // $x, array($i,$j) => sprintf($x, $i, $j)
143         $result = call_user_func_array("sprintf", $s);
144         if (in_array('link', $modes)) {
145             require_once("lib/InlineParser.php");
146             return TransformInline($result, 2, $basepage);
147         } else {
148             return HTML::raw($result);
149         }
150     }
151
152     function magic($file) {
153         if (function_exists('finfo_file') or loadPhpExtension('fileinfo')) {
154             // Valid finfo_open (i.e. libmagic) options:
155             // FILEINFO_NONE | FILEINFO_SYMLINK | FILEINFO_MIME | FILEINFO_COMPRESS | FILEINFO_DEVICES |
156             // FILEINFO_CONTINUE | FILEINFO_PRESERVE_ATIME | FILEINFO_RAW
157             $f = finfo_open(/*FILEINFO_MIME*/);
158             $result = finfo_file(realpath($file));
159             finfo_close($res);
160             return $result;
161         }
162         return '';
163     }
164
165     function mime_type($file) {
166         return '';
167     }
168
169     function _formatsize ($n, $factor, $suffix = '') {
170         if ($n > $factor) {
171             $b = $n / $factor;
172             $n -= floor($factor * $b);
173             return number_format($b, $n ? 3 : 0). $suffix;
174         }
175     }
176     function phonysize ($a) {
177         $factor = 1024 * 1024 * 1000;
178         if ($a > $factor)
179             return $this->_formatsize($a, $factor, ' GB');
180         $factor = 1024 * 1000;
181         if ($a > $factor)
182             return $this->_formatsize($a, $factor, ' MB');
183         $factor = 1024;
184         if ($a > $factor)
185             return $this->_formatsize($a, $factor, ' KB');
186         if ($a > 1)
187             return $this->_formatsize($a, 1, ' byte');
188         else
189             return $a;
190     }
191
192     function exeversion($file) {
193         if (!isWindows()) return "?";
194         if (class_exists('ffi') or loadPhpExtension('ffi'))
195             return $this->exeversion_ffi($file);
196         if (function_exists('res_list_type') or loadPhpExtension('win32std'))
197             return $this->exeversion_resopen($file);
198         return exeversion_showver($file);
199         return '';
200     }
201
202     // http://www.codeproject.com/dll/showver.asp
203     function exeversion_showver($file) {
204         $path = realpath($file);
205         $result = `showver $path`; 
206         return "?";
207     }
208
209     function exeversion_ffi($file) {
210         if (!DEBUG)
211             return "?"; // not yet stable
212         
213         if (function_exists('ffi') or loadPhpExtension('ffi')) {
214             $win32_idl = "
215 struct VS_FIXEDFILEINFO {
216         DWORD dwSignature;
217         DWORD dwStrucVersion;
218         DWORD dwFileVersionMS;
219         DWORD dwFileVersionLS;
220         DWORD dwProductVersionMS;
221         DWORD dwProductVersionLS;
222         DWORD dwFileFlagsMask;
223         DWORD dwFileFlags;
224         DWORD dwFileOS;
225         DWORD dwFileType;
226         DWORD dwFileSubtype;
227         DWORD dwFileDateMS;
228         DWORD dwFileDateLS;
229 };
230 struct VS_VERSIONINFO { struct VS_VERSIONINFO
231   WORD  wLength; 
232   WORD  wValueLength; 
233   WORD  wType; 
234   WCHAR szKey[1]; 
235   WORD  Padding1[1]; 
236   VS_FIXEDFILEINFO Value; 
237   WORD  Padding2[1]; 
238   WORD  Children[1]; 
239 };
240 [lib='kernel32.dll'] DWORD GetFileVersionInfoSizeA(char *szFileName, DWORD *dwVerHnd);
241 [lib='kernel32.dll'] int GetFileVersionInfoA(char *sfnFile, DWORD dummy, DWORD size, struct VS_VERSIONINFO *pVer);
242 ";
243             $ffi = new ffi($win32_idl);
244             $dummy = 0; // &DWORD
245             $size = $ffi->GetFileVersionInfoSizeA($file, $dummy);
246             //$pVer = str_repeat($size+1);
247             $pVer = new ffi_struct($ffi, "VS_VERSIONINFO");
248             if ($ffi->GetFileVersionInfoA($file, 0, $size, $pVer) 
249                 and $pVer->wValueLength) {
250                 // analyze the VS_FIXEDFILEINFO(Value);
251                 // $pValue = new ffi_struct($ffi, "VS_FIXEDFILEINFO");
252                 $pValue =& $pVer->Value;
253                 return sprintf("%d.%d.%d.%d",
254                                $pValue->dwFileVersionMS >> 16,
255                                $pValue->dwFileVersionMS & 0xFFFF,
256                                $pValue->dwFileVersionLS >> 16, 
257                                $pValue->dwFileVersionLS & 0xFFFF);
258             }
259         }
260     }
261
262     // Read "RT_VERSION/VERSIONINFO" exe/dll resource info for MSWin32 binaries
263     // The "win32std" extension is not ready yet to pass back a VERSIONINFO struct
264     function exeversion_resopen($file) {
265         if (function_exists('res_list_type') or loadPhpExtension('win32std')) {
266             // See http://msdn.microsoft.com/workshop/networking/predefined/res.asp
267             $v = file_get_contents('res://'.realpath($file).urlencode('/RT_VERSION/#1'));
268             if ($v) {
269                 // This is really a binary VERSIONINFO block, with lots of
270                 // nul bytes (widechar) which cannot be transported as string.
271                 return "$v";
272             }
273             else {
274                 $h = res_open(realpath($file));
275                 $v = res_get($h, 'RT_VERSION', 'FileVersion');
276                 res_close($h);
277                 if ($v) return $v;
278
279                 $h = res_open(realpath($file));
280                 $v = res_get($h, '#1', 'RT_VERSION', 1);
281                 res_close($h);
282                 if ($v) return $v;
283             }
284               
285             /* The version consists of two 32-bit integers, defined by four 16-bit integers. 
286                For example, "FILEVERSION 3,10,0,61" is translated into two doublewords: 
287                0x0003000a and 0x0000003d, in that order. */
288 /*          
289         $h = res_open(realpath($file));
290             
291         echo "Res list of '$file': \n";
292         $list= res_list_type($h, true);
293         if( $list===FALSE ) err( "Can't list type" );
294         
295         for( $i= 0; $i<count($list); $i++ ) {
296                 echo $list[$i]."\n";
297                 $res= res_list($h, $list[$i]);
298                 for( $j= 0; $j<count($res); $j++ ) {
299                         echo "\t".$res[$j]."\n";
300                 }
301         }
302         echo "Res get: ".res_get( $h, 'A_TYPE', 'A_RC_NAME' )."\n\n";
303         res_close( $h );            
304 */
305             if ($v)
306                 return "$v";
307             else 
308                 return "";
309         } else {
310             return "";
311         }
312         
313     }
314 };
315
316 // For emacs users
317 // Local Variables:
318 // mode: php
319 // tab-width: 8
320 // c-basic-offset: 4
321 // c-hanging-comment-ender-p: nil
322 // indent-tabs-mode: nil
323 // End:
324 ?>