%PDF- %PDF-
Direktori : /home1/lightco1/www/plugins/content/sigplus/core/ |
Current File : //home1/lightco1/www/plugins/content/sigplus/core/filesystem.php |
<?php /** * @file * @brief sigplus Image Gallery Plus file system functions * @author Levente Hunyadi * @version 1.5.0 * @remarks Copyright (C) 2009-2017 Levente Hunyadi * @remarks Licensed under GNU/GPLv3, see http://www.gnu.org/licenses/gpl-3.0.html * @see http://hunyadi.info.hu/sigplus */ /* * sigplus Image Gallery Plus plug-in for Joomla * Copyright 2009-2017 Levente Hunyadi * * sigplus is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * sigplus is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /***************************************************************************** * UTF-8 file system compatibility layer *****************************************************************************/ if (!interface_exists('fsx_functions') && !class_exists('fsx')) { /** * UTF-8 compatibility layer for filesystem functions. * * This layer exposes PHP 5 filesystem functions like file_exists, filesize, filemtime, readfile, * etc. that support files whose filename contains UTF-8 (non-ASCII) characters. Prefix function * names with the static class name "fsx" to unlock functionality. For instance, the statement * * $size = fsx::filesize($file); * * returns the file size in bytes even if the variable $file contains non-ASCII characters. * * Normally, PHP 4/5 filesystem functions use ANSI versions of Windows filesystem functions, which * fail with non-ASCII characters in filenames. This thin layer uses COM scripting services to * interact with the Windows filesystem in a way that makes it possible to pass UTF-8 characters * in filenames. */ interface fsx_functions { public function scandir($dir); public function scandir_files($dir); public function scandir_folders($dir); public function scandir_mtime($dir); public function get_files_with_extension($dir, array $ext, $rev = false); public function file_exists($path); public function filemtime($file); public function filesize($file); public function file_get_contents($file); public function file_put_contents($file, $data); public function readfile($file); } class fsx_windows implements fsx_functions { /** * A COM file system object in Windows. */ private $fs = null; public function __construct($fs) { $this->fs = $fs; } public function __destruct() { unset($this->fs); } private static function is_ascii($string) { return !preg_match('/[\\x80-\\xff]+/', $string); } public function get_short_path($path) { try { if ($this->fs->FileExists($path)) { return $this->fs->GetFile($path)->ShortPath; } if ($this->fs->FolderExists($path)) { return $this->fs->GetFolder($path)->ShortPath; } } catch (com_exception $e) {} return $path; // no short path available } public function scandir($dir) { $results = array(); try { $fsdir = $this->fs->GetFolder($dir); foreach ($fsdir->SubFolders as $fsfolder) { $results[] = $fsfolder->Name; } foreach ($fsdir->Files as $fsfile) { $results[] = $fsfile->Name; } unset($fsdir); return $results; } catch (com_exception $e) { } return false; } public function scandir_files($dir) { $results = array(); try { $fsdir = $this->fs->GetFolder($dir); foreach ($fsdir->Files as $fsfile) { $results[] = $fsfile->Name; } unset($fsdir); return $results; } catch (com_exception $e) { } return false; } public function scandir_folders($dir) { $results = array(); try { $fsdir = $this->fs->GetFolder($dir); foreach ($fsdir->SubFolders as $fsfolder) { $results[] = $fsfolder->Name; } unset($fsdir); return $results; } catch (com_exception $e) { } return false; } public function scandir_mtime($dir) { $results = array(); try { $fsdir = $this->fs->GetFolder($dir); foreach ($fsdir->Files as $fsfile) { $results[$fsfile->Name] = $fsfile->DateLastModified; } unset($fsdir); return $results; } catch (com_exception $e) { } return false; } /** * Get a directory listing in character set UTF-8. */ public function get_files_with_extension($dir, array $ext, $rev = false) { $results = array(); try { $fsdir = $this->fs->getFolder($dir); foreach ($fsdir->Files as $fsfile) { $fsname = $fsfile->Name; $fsext = ''; if (($pos = strrpos($fsname, '.')) !== false) { $fsext = substr($fsname, $pos + 1); // skip dot (.) } if (in_array($fsext, $ext)) { $results[] = $fsname; } } unset($fsdir); return $results; } catch (com_exception $e) { } return false; } public function file_exists($path) { return $this->fs->FileExists($path) || $this->fs->FolderExists($path); } public function filemtime($file) { try { if ($this->fs->FileExists($file)) { return variant_date_to_timestamp($this->fs->GetFile($file)->DateLastModified); } if ($this->fs->FolderExists($file)) { return variant_date_to_timestamp($this->fs->GetFolder($file)->DateLastModified); } } catch (com_exception $e) {} return false; } public function filesize($file) { try { if ($this->fs->FileExists($file)) { return $this->fs->GetFile($file)->Size; } } catch (com_exception $e) {} return false; } public function file_get_contents($file) { if (self::is_ascii($file)) { return file_get_contents($file); } $is_output_buffered = false; try { $stream = new COM('ADODB.Stream', null, CP_UTF8); // use UTF-8 code page for communicating with COM object $stream->Mode = 3; // adModeReadWrite $stream->Type = 1; // adTypeBinary $stream->Open(); $stream->LoadFromFile($file); // read file into Stream object $data = $stream->Read(); // convert to PHP Traversable $is_output_buffered = ob_start(); foreach ($data as $item) { // iterate COM SAFEARRAY as character codes and print each character print chr($item); } $string = ob_get_clean(); $stream->Close(); return $string; } catch (com_exception $e) { if ($is_output_buffered) { ob_end_clean(); } return file_get_contents($this->get_short_path($file)); } } public function file_put_contents($file, $data) { try { $tempfile = tempnam(dirname($file), 'fsx'); $result = file_put_contents($tempfile, $data); if ($this->fs->FileExists($file)) { $this->fs->DeleteFile($file); } $this->fs->MoveFile($tempfile, $file); return $result; } catch (com_exception $e) { if (isset($tempfile) && file_exists($tempfile)) { unlink($tempfile); } return false; } } public function readfile($file) { if (self::is_ascii($file)) { return readfile($file); } try { $stream = new COM('ADODB.Stream', null, CP_UTF8); // use UTF-8 code page for communicating with COM object $stream->Mode = 3; // adModeReadWrite $stream->Type = 1; // binary $stream->Open(); $stream->LoadFromFile($file); // read file into Stream object $data = $stream->Read(); // convert to PHP Traversable foreach ($data as $item) { // iterate COM SAFEARRAY as character codes and print each character print chr($item); } $stream->Close(); return true; } catch (com_exception $e) { return readfile($this->get_short_path($file)); } } public function getimagesize($file, &$info = null) { if (function_exists('getimagesizefromstring')) { return getimagesizefromstring($this->file_get_contents($file), $info); } else { return getimagesize($this->get_short_path($file), $info); } } public function imagecreatefromjpeg($file) { $content = $this->file_get_contents($file); return @imagecreatefromstring($content); } public function imagecreatefromgif($file) { $content = $this->file_get_contents($file); return @imagecreatefromstring($content); } public function imagecreatefrompng($file) { $content = $this->file_get_contents($file); return @imagecreatefromstring($content); } public function imagejpeg($image, $file, $quality) { ob_start(); imagejpeg($image, null, $quality); $data = ob_get_clean(); if ($data !== false) { $this->file_put_contents($file, $data); return true; } else { return false; } } public function imagegif($image, $file) { ob_start(); imagegif($image); $data = ob_get_clean(); if ($data !== false) { $this->file_put_contents($file, $data); return true; } else { return false; } } public function imagepng($image, $file, $quality) { ob_start(); imagepng($image, null, $quality); $data = ob_get_clean(); if ($data !== false) { $this->file_put_contents($file, $data); return true; } else { return false; } } } class fsx_unix implements fsx_functions { public function scandir($dir) { return scandir($dir); } public function scandir_files($dir) { $entries = scandir($dir); if ($entries !== false) { $results = array(); foreach ($entries as $entry) { if (is_file($dir.DIRECTORY_SEPARATOR.$entry)) { $results[] = $entry; } } return $results; } else { return false; } } public function scandir_folders($dir) { $entries = scandir($dir); if ($entries !== false) { $results = array(); foreach ($entries as $entry) { if (is_dir($dir.DIRECTORY_SEPARATOR.$entry)) { $results[] = $entry; } } return $results; } else { return false; } } /** * List files and directories inside the specified path with modification time. * @return An associative array with filenames as keys and timestamps as values. */ public function scandir_mtime($dir) { $dh = @opendir($dir); if ($dh === false) { // cannot open directory return false; } $files = array(); while (false !== ($filename = readdir($dh))) { if (!is_regular_file($filename)) { continue; } $files[$filename] = filemtime($dir.DIRECTORY_SEPARATOR.$filename); } closedir($dh); return $files; } /** * Get all files in a directory that have the specified extension. * @param {string} $dir Absolute path to a directory. * @param {string} $ext Extension to check file names against. * @param {boolean} $rev True if file names are to be sorted in reverse order. */ public function get_files_with_extension($dir, array $ext, $rev = false) { $results = array(); $files = scandir($dir, $rev); foreach ($files as $file) { if (in_array(pathinfo($file, PATHINFO_EXTENSION), $ext)) { $results[] = $file; } } return $results; } public function file_exists($path) { return file_exists($path); } public function filemtime($file) { return filemtime($file); } public function filesize($file) { return filesize($file); } public function file_get_contents($file) { return file_get_contents($file); } public function file_put_contents($file, $data) { return file_put_contents($file, $data); } public function readfile($file) { return readfile($file); } public function getimagesize($file, &$info = null) { return getimagesize($file, $info); // no special wrapper is required for UNIX-style operating systems } public function imagecreatefromjpeg($file) { return imagecreatefromjpeg($file); // no special wrapper is required for UNIX-style operating systems } public function imagecreatefromgif($file) { return imagecreatefromgif($file); // no special wrapper is required for UNIX-style operating systems } public function imagecreatefrompng($file) { return imagecreatefrompng($file); // no special wrapper is required for UNIX-style operating systems } public function imagejpeg($image, $file, $quality) { return imagejpeg($image, $file, $quality); } public function imagegif($image, $file) { return imagegif($image, $file); } public function imagepng($image, $file, $quality) { return imagepng($image, $file, $quality); } } /** * File system extensions. * File system portability layer for Windows and UNIX-based systems. */ class fsx { private static $instance; public static function initialize() { $fs = false; if (class_exists('COM')) { try { $fs = new COM('Scripting.FileSystemObject', null, CP_UTF8); } catch (com_exception $e) { } } if ($fs !== false) { self::$instance = new fsx_windows($fs); // use Windows FileSystemObject } else { // COM Scripting not available self::$instance = new fsx_unix(); // use PHP's own functions with a thin wrapper } } public static function scandir($dir) { return self::$instance->scandir($dir); } public static function scandir_files($dir) { return self::$instance->scandir_files($dir); } public static function scandir_folders($dir) { return self::$instance->scandir_folders($dir); } public static function scandir_mtime($dir) { return self::$instance->scandir_mtime($dir); } public static function get_files_with_extension($dir, $ext, $rev = false) { if (!is_array($ext)) { $ext = array($ext); } return self::$instance->get_files_with_extension($dir, $ext, $rev); } /** * Get all files in a directory that have the specified extension sorted by last modified time. * @param {string} $dir Absolute path to a directory. * @param {string} $ext Extension to check file names against. * @param {boolean} $rev True if file names are to be sorted in reverse order. */ public static function get_files_with_extension_time($dir, $ext, $rev = false) { $files = self::$instance->get_files_with_extension($dir, $ext, $rev); // fetch last modified date for each file $times = array(); foreach ($files as $file) { $times[] = self::filemtime($dir.DIRECTORY_SEPARATOR.$file); } // sort file array based on timestamp values $sortorder = $rev ? SORT_DESC : SORT_ASC; array_multisort($times, $sortorder, SORT_NUMERIC, $files, $sortorder, SORT_STRING); return $files; } public static function file_exists($path) { return self::$instance->file_exists($path); } public static function filemtime($file) { return self::$instance->filemtime($file); } public static function filesize($file) { return self::$instance->filesize($file); } public static function file_get_contents($file) { return self::$instance->file_get_contents($file); } public static function file_put_contents($file, $data) { return self::$instance->file_put_contents($file, $data); } public static function readfile($file) { return self::$instance->readfile($file); } public static function getimagesize($file, &$info = null) { return self::$instance->getimagesize($file, $info); } public static function imagecreatefromjpeg($file) { return self::$instance->imagecreatefromjpeg($file); } public static function imagecreatefromgif($file) { return self::$instance->imagecreatefromgif($file); } public static function imagecreatefrompng($file) { return self::$instance->imagecreatefrompng($file); } public static function imagejpeg($image, $file, $quality) { return self::$instance->imagejpeg($image, $file, $quality); } public static function imagegif($image, $file) { return self::$instance->imagegif($image, $file); } public static function imagepng($image, $file, $quality) { return self::$instance->imagepng($image, $file, $quality); } public static function filemdate($file) { return gmdate('Y-m-d H:i:s', fsx::filemtime($file)); } } fsx::initialize(); } // if (!interface_exists('fsx_functions') && !class_exists('fsx')) /***************************************************************************** * Directory listing *****************************************************************************/ if (!function_exists('walkdir')) { /** * List files and directories inside the specified path recursively. * @param {string} $path The directory whose files and subdirectories to list. * @param {array} $exclude Subdirectories to exclude from the listing. * @param {int} $depth Maximum depth to traverse the directory hierarchy; >0 for recursive directory listing with a limit, 0 for flat listing, or -1 for listing with no limit. * @param $callback Callback function to invoke for each directory hierarchy level. * @param {array} $ancestors Breadcrumbs for current directory ancestors returned by the callback function */ function walkdir($path, array $exclude = array(), $depth = 0, $callback = null, $ancestors = null) { $folders = fsx::scandir_folders($path); $files = fsx::scandir_files($path); if ($folders === false || $files === false) { return; } foreach ($folders as $key => $folder) { if ($folder == '.' || $folder == '..' || in_array($folder, $exclude)) { // skip special directory entries "." and "..", as well as excluded entries unset($folders[$key]); } } foreach ($files as $key => $file) { if ($file{0} == '.' && in_array($file, $exclude)) { // skip hidden files and excluded entries unset($files[$key]); } } // invoke callback function if (isset($callback)) { if (is_array($callback)) { $object = $callback[0]; $params = $callback[1]; $func = array($object, $params); } else { $func = $callback; } if (isset($ancestors)) { $ancestor = call_user_func($func, $path, $files, $folders, $ancestors); array_unshift($ancestors, $ancestor); // add current folder to list of ancestors } else { call_user_func($func, $path, $files, $folders); } } // scan descandant folders if ($depth < 0 || $depth > 0) { foreach ($folders as $folder) { if (isset($ancestors)) { walkdir($path.DIRECTORY_SEPARATOR.$folder, $exclude, $depth - 1, $callback, $ancestors); } else { walkdir($path.DIRECTORY_SEPARATOR.$folder, $exclude, $depth - 1, $callback); } } } } } // if (!function_exists('walkdir')) /***************************************************************************** * Miscellaneous file system management. *****************************************************************************/ /** * Ensure that a string is a relative path, removing leading and trailing space and slashes from a path string. */ function relativepath($path) { return str_replace('\\', '/', trim($path, "\t\n\r /")); // remove leading and trailing spaces and slashes } /** * Ensures that all components of a URL are URL-encoded. */ function safe_url_encode($url) { $urlparts = parse_url($url); $pattern = '#^([0-9A-Za-z!"$&\'()*+,.:;=@_-]|%[0-9A-Za-z]{2})+$#'; $segments = explode('/', $urlparts['path']); foreach ($segments as &$segment) { if (!preg_match($pattern, $segment)) { // path segment contains a character that has not been URL-encoded $segment = rawurlencode($segment); } } $urlparts['path'] = implode('/', $segments); if (!empty($urlparts['query'])) { if (!preg_match($pattern, $urlparts['query'])) { // query contains a character that has not been URL-encoded $urlparts['query'] = rawurlencode($urlparts['query']); } } return $urlparts['scheme'].'://'. ( empty($urlparts['user']) ? '' : $urlparts['user'].( empty($urlparts['pass']) ? '' : ':'.$urlparts['pass'] ).'@' ). $urlparts['host'].$urlparts['path']. ( empty($urlparts['query']) ? '' : '?'.$urlparts['query'] ). ( empty($urlparts['fragment']) ? '' : '#'.$urlparts['fragment'] ); } /** * URL-encodes all components of a path. */ function path_url_encode($path) { $parts = explode('/', strtr($path, DIRECTORY_SEPARATOR, '/')); if (preg_match('#^[A-Za-z0-9]:$#S', $parts[0])) { // a Windows-style path with drive letter $firstpart = array_shift($parts); // do not URL-encode drive letter foreach ($parts as &$part) { $part = rawurlencode($part); } array_unshift($parts, $firstpart); } else { foreach ($parts as &$part) { $part = rawurlencode($part); } } return implode('/', $parts); } /** * URL-decodes all components of a path. */ function path_url_decode($path) { $parts = explode('/', $path); foreach ($parts as &$part) { $part = rawurldecode($part); } return implode(DIRECTORY_SEPARATOR, $parts); } /** * Tests whether a string is a HTTP URL. */ function is_url_http($string) { return preg_match('#^https?://#', $string); } /** * Check if a path is a UNIX- or Windows-style absolute file system path. */ function is_absolute_path($path) { return (bool) preg_match('#^(/|([A-Za-z0-9]:)?\\\\)#S', $path); } /** * Filters regular files, skipping those that are hidden. * The filename of a hidden file starts with a dot. */ function is_regular_file($filename) { return $filename{0} != '.'; } function is_filename($filename) { return strpos(strtr($filename, DIRECTORY_SEPARATOR, '/'), '/') === false; } /** * Checks whether a file or directory exists accepting both lowercase and uppercase extension. * @return The file name with extension as found in the file system. */ function file_exists_case_insensitive($path) { $realpath = realpath($path); if ($realpath !== false) { return pathinfo($realpath, PATHINFO_BASENAME); // file name possibly with extension } $filename = pathinfo($path, PATHINFO_BASENAME); // file name possibly with extension if (fsx::file_exists($path)) { // file exists as-is, no inspection of extension is necessary return $filename; } $extension = pathinfo($path, PATHINFO_EXTENSION); // file extension if present if ($extension) { // if file has extension $p = strrpos($path, '.'); // starting position of extension (incl. dot) $base = substr($path, 0, $p); // everything up to extension $extension = substr($path, $p); // extension (incl. dot) $p = strrpos($filename, '.'); $filename = substr($filename, 0, $p); // drop extension from filename $extension = strtolower($extension); if (fsx::file_exists($base.$extension)) { // file with lowercase extension return $filename.$extension; } $extension = strtoupper($extension); if (fsx::file_exists($base.$extension)) { // file with uppercase extension return $filename.$extension; } } return false; // file not found } /** * Escapes characters with special meaning to `glob`. */ function glob_escape($str) { return str_replace(array('[', ']'), array('\\[', '\\]'), $str); } /** * Returns a canonicalized absolute pathname with case-insensitive search. * @param path The path to canonicalize with case-insensitive search. * @return The expanded path string, with character case matching the version stored in the file system. */ function realpath_case_insensitive($path) { // check if path exists with case-sensitive match $real_path = realpath($path); if ($real_path !== false) { return $real_path; } // check if path exists with case-insensitive match $dir = dirname($path); if ($dir === $path) { return false; } $dir = realpath_case_insensitive($dir); if ($dir === false) { return false; } $basename = basename($path); $lower = strtolower($basename); $upper = strtoupper($basename); $pattern = ''; for ($pos = 0, $len = strlen($lower); $pos < $len; ++$pos) { if ($lower[$pos] != $upper[$pos]) { $pattern .= sprintf('[%s%s]', glob_escape($lower[$pos]), glob_escape($upper[$pos])); } else { $pattern .= glob_escape($lower[$pos]); } } return current(glob($dir . DIRECTORY_SEPARATOR . $pattern, GLOB_NOSORT)); } /** * Returns a canonicalized absolute pathname with case-insensitive search. * @param path The path to canonicalize with case-insensitive search. * @return The expanded path string, with character case matching the version stored in the file system. */ function realpathi($path) { $path = rtrim(preg_replace('#[/\\\\]+#', DIRECTORY_SEPARATOR, $path), DIRECTORY_SEPARATOR); return realpath_case_insensitive($path); } /** * Get the lastest time the folder or one of its descendants has been modified. * @param {string} $dir An absolute path to a folder. * @param {int} $depth 0 for current folder only, 1 for current and children, n (>1) for descandants until the given limit, -1 for all descendants. */ function get_folder_last_modified($dir, $depth = 0) { $mtime = fsx::filemtime($dir); if ($depth != 0) { // scan directory for last modified descandant folder if ($dh = @opendir($dir)) { while (($entry = readdir($dh)) !== false) { if ($entry != '.' && $entry != '..' && is_dir($dir.DIRECTORY_SEPARATOR.$entry)) { $mtime = max($mtime, get_folder_last_modified($dir.DIRECTORY_SEPARATOR.$entry, $depth - 1)); } } closedir($dh); } } return $mtime; } /** * Fetch a resource, validating it against a (weak) entity tag. * If the resource pointed to by the entity tag has expired, the resource is fetched. * @param {string} $url The URL to retrieve. * @param {string} $last_modified Last modified UTC date in format YYYY-MM-DD HH:MM:SS. * @param {string} $etag A (weak) entity tag. * @param {array} $request_headers HTTP request headers. */ function http_get_modified($url, $last_modified = null, $etag = null, $method = 'GET', $request_headers = array()) { $data = false; $response_headers = false; // add If-Modified-Since header if (!empty($last_modified)) { $date = DateTime::createFromFormat('Y-m-d H:i:s', $last_modified, new DateTimeZone('UTC')); $request_headers[] = 'If-Modified-Since: '.$date->format('D, d M Y H:i:s T'); } // add If-None-Match header (a.k.a ETag) if (!empty($etag)) { $request_headers[] = 'If-None-Match: '.$etag; } // create stream context if (!empty($request_headers)) { $options = array( 'http' => array( 'method' => $method, 'header' => implode("\r\n", $request_headers)."\r\n" ) ); $context = stream_context_create($options); $stream = fopen($url, 'r', false, $context); } else { $stream = fopen($url, 'r'); } // test for HTTP ETag match, $http_response_header is a predefined PHP variable if (!isset($http_response_header)) { // HTTP wrappers are disabled $data = false; // cannot access resource } elseif (!preg_match('#^HTTP/[\d.]+\s+(\d+)#S', $http_response_header[0], $matches) || $matches[1] != '304') { // HTTP 304 "Not modified" indicates ETag match $response_headers = $http_response_header; foreach ($http_response_header as $header) { // go through header lines, looking for HTTP ETag if (preg_match('#^ETag:\s+(\S+)#iS', $header, $matches)) { // locate ETag header $response_headers['ETag'] = $matches[1]; // extract and update ETag value break; } elseif (preg_match('#^Last-Modified:\s+(.+)$#iS', $header, $matches)) { $timestring = $matches[1]; if (version_compare(PHP_VERSION, '5.3.0') >= 0) { $date = DateTime::createFromFormat('D, d M Y H:i:s T', $timestring); // parse HTTP date format (RFC 822, updated by RFC 1123) } else { $unixtime = strtotime($timestring); if ($unixtime !== false && $unixtime !== -1) { $date = new DateTime('@'.$unixtime); } else { $date = false; } } if ($date !== false) { $response_headers['Last-Modified'] = $date->format('Y-m-d H:i:s'); // generate database date format } } elseif (preg_match('#^Content-Length:\s+(\d+)$#iS', $header, $matches)) { $response_headers['Content-Length'] = (int)($matches[1]); // extract and update ETag value } } if ($stream !== false) { // read data if HTTP ETag does not match $data = stream_get_contents($stream); } else { $data = false; // cannot access resource } } else { $data = true; // resource not modified } // close stream if ($stream !== false) { fclose($stream); } return array($data, $response_headers); } /** * Compute an image hash. */ function image_hash($imagepath, $userdata = false, $secret = false, $size = false) { if ($size === false) { $size = @fsx::getimagesize($imagepath); } if ($size !== false) { return sha1($secret.$userdata.$imagepath.'_'.$size[0].'x'.$size[1]); } else { return false; } }