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