3 * Copyright © 2005,2007 $ThePhpWikiProgrammingTeam
4 * Copyright © 2008-2009 Marc-Etienne Vargenau, Alcatel-Lucent
6 * This file is part of PhpWiki.
8 * PhpWiki is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * PhpWiki is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 * SPDX-License-Identifier: GPL-2.0-or-later
27 * This plugin displays the version, date, size, perms of an uploaded file.
28 * Only files relative and below to the uploads path can be handled.
31 * <<FileInfo file=Upload:setup.exe display=version,date >>
32 * <<FileInfo file=Upload:setup.exe display=name,version,date
33 * format="%s (version: %s, date: %s)" >>
35 * @author: Reini Urban
38 class WikiPlugin_FileInfo
41 function getDescription()
43 return _("Display file information like version, size, date... of uploaded files.");
46 function getDefaultArguments()
49 'file' => false, // relative path from PHPWIKI_DIR. (required)
50 'display' => false, // version,phonysize,size,date,mtime,owner,name,path,dirname,link. (required)
51 'format' => false, // printf format string with %s only, all display modes
52 'quiet' => false // print no error if file not found
53 // from above vars return strings (optional)
59 * @param string $argstr
60 * @param WikiRequest $request
61 * @param string $basepage
64 function run($dbi, $argstr, &$request, $basepage)
66 $args = $this->getArgs($argstr, $request);
69 return $this->error(sprintf(_("A required argument “%s” is missing."), 'file'));
72 return $this->error(sprintf(_("A required argument “%s” is missing."), 'display'));
74 if (string_starts_with($file, "Upload:")) {
75 $file = preg_replace("/^Upload:(.*)$/", getUploadFilePath() . "\\1", $file);
79 if (defined('PHPWIKI_DIR')) {
82 if (!file_exists($file)) {
86 return $this->error(sprintf(_("File “%s” not found."), $file));
90 $realfile = realpath($file);
91 // Hmm, allow ADMIN to check a local file? Only if its locked
92 if (string_starts_with($realfile, realpath(getUploadDataPath()))) {
95 $page = $dbi->getPage($basepage);
96 $user = $request->getUser();
97 if ($page->getOwner() != ADMIN_USER or !$page->get('locked')) {
98 // For convenience we warn the admin
99 if ($quiet and $user->isAdmin())
100 return HTML::span(array('title' => _("Output suppressed. FileInfoPlugin with local files require a locked page.")),
101 HTML::em(_("page not locked")));
103 return $this->error("Invalid path \"$file\". Only ADMIN can allow local paths, and the page must be locked.");
107 $modes = explode(",", $display);
108 foreach ($modes as $mode) {
111 $s[] = $this->exeversion($file);
114 $s[] = filesize($file);
117 $s[] = $this->phonysize(filesize($file));
120 $s[] = strftime("%x %X", filemtime($file));
123 $s[] = filemtime($file);
126 $o = posix_getpwuid(fileowner($file));
130 $o = posix_getgrgid(filegroup($file));
134 $s[] = basename($file);
140 $s[] = dirname($file);
143 $s[] = $this->magic($file);
146 $s[] = $this->mime_type($file);
150 $s[] = " [" . $args['file'] . "]";
151 } elseif ($isuploaded) {
152 // will fail with user uploads
153 $s[] = " [Upload:" . basename($file) . "]";
155 $s[] = " [" . basename($file) . "] ";
160 return $this->error(sprintf(_("Unsupported argument: %s=%s"), 'display', $mode));
162 return HTML::raw('');
174 array_unshift($s, $format);
175 // $x, array($i,$j) => sprintf($x, $i, $j)
176 $result = call_user_func_array("sprintf", $s);
177 if (in_array('link', $modes)) {
178 require_once 'lib/InlineParser.php';
179 return TransformInline($result, $basepage);
181 return HTML::raw($result);
185 function magic($file)
187 // Valid finfo_open (i.e. libmagic) options:
188 // FILEINFO_NONE | FILEINFO_SYMLINK | FILEINFO_MIME | FILEINFO_COMPRESS | FILEINFO_DEVICES |
189 // FILEINFO_CONTINUE | FILEINFO_PRESERVE_ATIME | FILEINFO_RAW
190 $f = finfo_open( /*FILEINFO_MIME*/);
191 $result = finfo_file(realpath($file));
196 function mime_type($file)
201 private function _formatsize($n, $factor, $suffix = '')
205 $n -= floor($factor * $b);
206 return number_format($b, $n ? 3 : 0) . $suffix;
211 function phonysize($a)
213 $factor = 1024 * 1024 * 1000;
215 return $this->_formatsize($a, $factor, ' GB');
216 $factor = 1024 * 1000;
218 return $this->_formatsize($a, $factor, ' MB');
221 return $this->_formatsize($a, $factor, ' KB');
223 return $this->_formatsize($a, 1, ' byte');
228 function exeversion($file)
230 if (!isWindows()) return "?";
231 if (class_exists('ffi') or loadPhpExtension('ffi'))
232 return $this->exeversion_ffi($file);
233 if (function_exists('res_list_type') or loadPhpExtension('win32std'))
234 return $this->exeversion_resopen($file);
235 return exeversion_showver($file);
238 // http://www.codeproject.com/dll/showver.asp
239 function exeversion_showver($file)
241 $path = realpath($file);
242 $result = `showver $path`;
246 function exeversion_ffi($file)
249 return "?"; // not yet stable
251 if (function_exists('ffi') or loadPhpExtension('ffi')) {
253 struct VS_FIXEDFILEINFO {
255 DWORD dwStrucVersion;
256 DWORD dwFileVersionMS;
257 DWORD dwFileVersionLS;
258 DWORD dwProductVersionMS;
259 DWORD dwProductVersionLS;
260 DWORD dwFileFlagsMask;
268 struct VS_VERSIONINFO { struct VS_VERSIONINFO
274 VS_FIXEDFILEINFO Value;
278 [lib='kernel32.dll'] DWORD GetFileVersionInfoSizeA(char *szFileName, DWORD *dwVerHnd);
279 [lib='kernel32.dll'] int GetFileVersionInfoA(char *sfnFile, DWORD dummy, DWORD size, struct VS_VERSIONINFO *pVer);
281 $ffi = new ffi($win32_idl);
282 $dummy = 0; // &DWORD
283 $size = $ffi->GetFileVersionInfoSizeA($file, $dummy);
284 //$pVer = str_repeat($size+1);
285 $pVer = new ffi_struct($ffi, "VS_VERSIONINFO");
286 if ($ffi->GetFileVersionInfoA($file, 0, $size, $pVer)
287 and $pVer->wValueLength
289 // analyze the VS_FIXEDFILEINFO(Value);
290 // $pValue = new ffi_struct($ffi, "VS_FIXEDFILEINFO");
291 $pValue =& $pVer->Value;
292 return sprintf("%d.%d.%d.%d",
293 $pValue->dwFileVersionMS >> 16,
294 $pValue->dwFileVersionMS & 0xFFFF,
295 $pValue->dwFileVersionLS >> 16,
296 $pValue->dwFileVersionLS & 0xFFFF);
302 // Read "RT_VERSION/VERSIONINFO" exe/dll resource info for MSWin32 binaries
303 // The "win32std" extension is not ready yet to pass back a VERSIONINFO struct
304 function exeversion_resopen($file)
306 if (function_exists('res_list_type') or loadPhpExtension('win32std')) {
307 // See http://msdn.microsoft.com/workshop/networking/predefined/res.asp
308 $v = file_get_contents('res://' . realpath($file) . urlencode('/RT_VERSION/#1'));
310 // This is really a binary VERSIONINFO block, with lots of
311 // nul bytes (widechar) which cannot be transported as string.
314 $h = res_open(realpath($file));
315 $v = res_get($h, 'RT_VERSION', 'FileVersion');
319 $h = res_open(realpath($file));
320 $v = res_get($h, '#1', 'RT_VERSION', 1);
325 /* The version consists of two 32-bit integers, defined by four 16-bit integers.
326 For example, "FILEVERSION 3,10,0,61" is translated into two doublewords:
327 0x0003000a and 0x0000003d, in that order. */
329 $h = res_open(realpath($file));
331 echo "Res list of '$file': \n";
332 $list= res_list_type($h, true);
333 if( $list===FALSE ) err( "Can't list type" );
335 for( $i= 0; $i<count($list); $i++ ) {
337 $res= res_list($h, $list[$i]);
338 for( $j= 0; $j<count($res); $j++ ) {
339 echo "\t".$res[$j]."\n";
342 echo "Res get: ".res_get( $h, 'A_TYPE', 'A_RC_NAME' )."\n\n";