update Piwik to version 2.16 (fixes #91)
This commit is contained in:
parent
296343bf3b
commit
d885a4baa9
5833 changed files with 418860 additions and 226988 deletions
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
|
|
@ -9,11 +9,13 @@
|
|||
namespace Piwik;
|
||||
|
||||
use Exception;
|
||||
use Piwik\Tracker\Cache;
|
||||
use Piwik\Container\StaticContainer;
|
||||
use Piwik\Tracker\Cache as TrackerCache;
|
||||
use Piwik\Cache as PiwikCache;
|
||||
|
||||
/**
|
||||
* Contains helper functions that deal with the filesystem.
|
||||
*
|
||||
*
|
||||
*/
|
||||
class Filesystem
|
||||
{
|
||||
|
|
@ -25,7 +27,9 @@ class Filesystem
|
|||
{
|
||||
AssetManager::getInstance()->removeMergedAssets($pluginName);
|
||||
View::clearCompiledTemplates();
|
||||
Cache::deleteTrackerCache();
|
||||
TrackerCache::deleteTrackerCache();
|
||||
PiwikCache::flushAll();
|
||||
self::clearPhpCaches();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -38,25 +42,6 @@ class Filesystem
|
|||
return realpath(dirname(__FILE__) . "/..");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create .htaccess file in specified directory
|
||||
*
|
||||
* Apache-specific; for IIS @see web.config
|
||||
*
|
||||
* @param string $path without trailing slash
|
||||
* @param bool $overwrite whether to overwrite an existing file or not
|
||||
* @param string $content
|
||||
*/
|
||||
public static function createHtAccess($path, $overwrite = true, $content = "<Files \"*\">\n<IfModule mod_access.c>\nDeny from all\n</IfModule>\n<IfModule !mod_access_compat>\n<IfModule mod_authz_host.c>\nDeny from all\n</IfModule>\n</IfModule>\n<IfModule mod_access_compat>\nDeny from all\n</IfModule>\n</Files>\n")
|
||||
{
|
||||
if (SettingsServer::isApache()) {
|
||||
$file = $path . '/.htaccess';
|
||||
if ($overwrite || !file_exists($file)) {
|
||||
@file_put_contents($file, $content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the string is a valid filename
|
||||
* File names that start with a-Z or 0-9 and contain a-Z, 0-9, underscore(_), dash(-), and dot(.) will be accepted.
|
||||
|
|
@ -88,19 +73,17 @@ class Filesystem
|
|||
|
||||
/**
|
||||
* Attempts to create a new directory. All errors are silenced.
|
||||
*
|
||||
*
|
||||
* _Note: This function does **not** create directories recursively._
|
||||
*
|
||||
* @param string $path The path of the directory to create.
|
||||
* @param bool $denyAccess Whether to deny browser access to this new folder by
|
||||
* creating an **.htaccess** file.
|
||||
* @api
|
||||
*/
|
||||
public static function mkdir($path, $denyAccess = true)
|
||||
public static function mkdir($path)
|
||||
{
|
||||
if (!is_dir($path)) {
|
||||
// the mode in mkdir is modified by the current umask
|
||||
@mkdir($path, $mode = 0755, $recursive = true);
|
||||
@mkdir($path, self::getChmodForPath($path), $recursive = true);
|
||||
}
|
||||
|
||||
// try to overcome restrictive umask (mis-)configuration
|
||||
|
|
@ -111,10 +94,6 @@ class Filesystem
|
|||
// enough! we're not going to make the directory world-writeable
|
||||
}
|
||||
}
|
||||
|
||||
if ($denyAccess) {
|
||||
self::createHtAccess($path, $overwrite = false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -139,8 +118,9 @@ class Filesystem
|
|||
// and the return code 1. if NFS, it will return 0 and at least 2 lines of text.
|
||||
$command = "df -T -t nfs \"$sessionsPath\" 2>&1";
|
||||
|
||||
if (function_exists('exec')) // use exec
|
||||
{
|
||||
if (function_exists('exec')) {
|
||||
// use exec
|
||||
|
||||
$output = $returnCode = null;
|
||||
@exec($command, $output, $returnCode);
|
||||
|
||||
|
|
@ -150,13 +130,16 @@ class Filesystem
|
|||
) {
|
||||
return true;
|
||||
}
|
||||
} else if (function_exists('shell_exec')) // use shell_exec
|
||||
{
|
||||
} elseif (function_exists('shell_exec')) {
|
||||
// use shell_exec
|
||||
|
||||
$output = @shell_exec($command);
|
||||
if ($output) {
|
||||
$output = explode("\n", $output);
|
||||
if (count($output) > 1) // check if filesystem is NFS
|
||||
{
|
||||
$commandFailed = (false !== strpos($output, "no file systems processed"));
|
||||
$output = explode("\n", trim($output));
|
||||
if (!$commandFailed
|
||||
&& count($output) > 1) {
|
||||
// check if filesystem is NFS
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -167,7 +150,7 @@ class Filesystem
|
|||
|
||||
/**
|
||||
* Recursively find pathnames that match a pattern.
|
||||
*
|
||||
*
|
||||
* See {@link http://php.net/manual/en/function.glob.php glob} for more info.
|
||||
*
|
||||
* @param string $sDir directory The directory to glob in.
|
||||
|
|
@ -228,6 +211,77 @@ class Filesystem
|
|||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all files and directories that are present in the target directory but are not in the source directory.
|
||||
*
|
||||
* @param string $source Path to the source directory
|
||||
* @param string $target Path to the target
|
||||
*/
|
||||
public static function unlinkTargetFilesNotPresentInSource($source, $target)
|
||||
{
|
||||
$diff = self::directoryDiff($source, $target);
|
||||
$diff = self::sortFilesDescByPathLength($diff);
|
||||
|
||||
foreach ($diff as $file) {
|
||||
$remove = $target . $file;
|
||||
|
||||
if (is_dir($remove)) {
|
||||
@rmdir($remove);
|
||||
} else {
|
||||
self::deleteFileIfExists($remove);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort all given paths/filenames by its path length. Long path names will be listed first. This method can be
|
||||
* useful if you have for instance a bunch of files/directories to delete. By sorting them by lengh you can make
|
||||
* sure to delete all files within the folders before deleting the actual folder.
|
||||
*
|
||||
* @param string[] $files
|
||||
* @return string[]
|
||||
*/
|
||||
public static function sortFilesDescByPathLength($files)
|
||||
{
|
||||
usort($files, function ($a, $b) {
|
||||
// sort by filename length so we kinda make sure to remove files before its directories
|
||||
if ($a == $b) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (strlen($a) > strlen($b) ? -1 : 1);
|
||||
});
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the difference of directories. Compares $target against $source and returns a relative path to all files
|
||||
* and directories in $target that are not present in $source.
|
||||
*
|
||||
* @param $source
|
||||
* @param $target
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function directoryDiff($source, $target)
|
||||
{
|
||||
$sourceFiles = self::globr($source, '*');
|
||||
$targetFiles = self::globr($target, '*');
|
||||
|
||||
$sourceFiles = array_map(function ($file) use ($source) {
|
||||
return str_replace($source, '', $file);
|
||||
}, $sourceFiles);
|
||||
|
||||
$targetFiles = array_map(function ($file) use ($target) {
|
||||
return str_replace($target, '', $file);
|
||||
}, $targetFiles);
|
||||
|
||||
$diff = array_diff($targetFiles, $sourceFiles);
|
||||
|
||||
return array_values($diff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies a file from `$source` to `$dest`.
|
||||
*
|
||||
|
|
@ -241,29 +295,42 @@ class Filesystem
|
|||
*/
|
||||
public static function copy($source, $dest, $excludePhp = false)
|
||||
{
|
||||
static $phpExtensions = array('php', 'tpl', 'twig');
|
||||
|
||||
if ($excludePhp) {
|
||||
$path_parts = pathinfo($source);
|
||||
if (in_array($path_parts['extension'], $phpExtensions)) {
|
||||
if (self::hasPHPExtension($source)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!@copy($source, $dest)) {
|
||||
@chmod($dest, 0755);
|
||||
if (!@copy($source, $dest)) {
|
||||
$message = "Error while creating/copying file to <code>$dest</code>. <br />"
|
||||
. Filechecks::getErrorMessageMissingPermissions(self::getPathToPiwikRoot());
|
||||
throw new Exception($message);
|
||||
}
|
||||
$success = self::tryToCopyFileAndVerifyItWasCopied($source, $dest);
|
||||
|
||||
if (!$success) {
|
||||
$success = self::tryToCopyFileAndVerifyItWasCopied($source, $dest);
|
||||
}
|
||||
|
||||
if (!$success) {
|
||||
throw new Exception("Error while creating/copying file from $source to <code>$dest</code>. Content of copied file is different.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static function hasPHPExtension($file)
|
||||
{
|
||||
static $phpExtensions = array('php', 'tpl', 'twig');
|
||||
|
||||
$path_parts = pathinfo($file);
|
||||
|
||||
if (!empty($path_parts['extension'])
|
||||
&& in_array($path_parts['extension'], $phpExtensions)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the contents of a directory recursively from `$source` to `$target`.
|
||||
*
|
||||
*
|
||||
* @param string $source A directory or file to copy, eg. './tmp/latest'.
|
||||
* @param string $target A directory to copy to, eg. '.'.
|
||||
* @param bool $excludePhp Whether to avoid copying files if the file is related to PHP
|
||||
|
|
@ -274,7 +341,7 @@ class Filesystem
|
|||
public static function copyRecursive($source, $target, $excludePhp = false)
|
||||
{
|
||||
if (is_dir($source)) {
|
||||
self::mkdir($target, false);
|
||||
self::mkdir($target);
|
||||
$d = dir($source);
|
||||
while (false !== ($entry = $d->read())) {
|
||||
if ($entry == '.' || $entry == '..') {
|
||||
|
|
@ -311,4 +378,130 @@ class Filesystem
|
|||
|
||||
return @unlink($pathToFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of a file in the specified unit.
|
||||
*
|
||||
* @param string $pathToFile
|
||||
* @param string $unit eg 'B' for Byte, 'KB', 'MB', 'GB', 'TB'.
|
||||
*
|
||||
* @return float|null Returns null if file does not exist or the size of the file in the specified unit
|
||||
*
|
||||
* @throws Exception In case the unit is invalid
|
||||
*/
|
||||
public static function getFileSize($pathToFile, $unit = 'B')
|
||||
{
|
||||
$unit = strtoupper($unit);
|
||||
$units = array('TB' => pow(1024, 4),
|
||||
'GB' => pow(1024, 3),
|
||||
'MB' => pow(1024, 2),
|
||||
'KB' => 1024,
|
||||
'B' => 1);
|
||||
|
||||
if (!array_key_exists($unit, $units)) {
|
||||
throw new Exception('Invalid unit given');
|
||||
}
|
||||
|
||||
if (!file_exists($pathToFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$filesize = filesize($pathToFile);
|
||||
$factor = $units[$unit];
|
||||
$converted = $filesize / $factor;
|
||||
|
||||
return $converted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a file.
|
||||
*
|
||||
* @param string $file
|
||||
* @param bool $silenceErrors If true, no exception will be thrown in case removing fails.
|
||||
*/
|
||||
public static function remove($file, $silenceErrors = false)
|
||||
{
|
||||
if (!file_exists($file)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$result = @unlink($file);
|
||||
|
||||
// Testing if the file still exist avoids race conditions
|
||||
if (!$result && file_exists($file)) {
|
||||
if ($silenceErrors) {
|
||||
Log::warning('Failed to delete file ' . $file);
|
||||
} else {
|
||||
throw new \RuntimeException('Unable to delete file ' . $file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $path
|
||||
* @return int
|
||||
*/
|
||||
private static function getChmodForPath($path)
|
||||
{
|
||||
$pathIsTmp = StaticContainer::get('path.tmp');
|
||||
if (strpos($path, $pathIsTmp) === 0) {
|
||||
// tmp/* folder
|
||||
return 0750;
|
||||
}
|
||||
// plugins/* and all others
|
||||
return 0755;
|
||||
}
|
||||
|
||||
public static function clearPhpCaches()
|
||||
{
|
||||
if (function_exists('apc_clear_cache')) {
|
||||
apc_clear_cache(); // clear the system (aka 'opcode') cache
|
||||
}
|
||||
|
||||
if (function_exists('opcache_reset')) {
|
||||
@opcache_reset(); // reset the opcode cache (php 5.5.0+)
|
||||
}
|
||||
|
||||
if (function_exists('wincache_refresh_if_changed')) {
|
||||
@wincache_refresh_if_changed(); // reset the wincache
|
||||
}
|
||||
|
||||
if (function_exists('xcache_clear_cache') && defined('XC_TYPE_VAR')) {
|
||||
if (ini_get('xcache.admin.enable_auth')) {
|
||||
// XCache will not be cleared because "xcache.admin.enable_auth" is enabled in php.ini.
|
||||
} else {
|
||||
@xcache_clear_cache(XC_TYPE_VAR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function havePhpFilesSameContent($file1, $file2)
|
||||
{
|
||||
if (self::hasPHPExtension($file1)) {
|
||||
$sourceMd5 = md5_file($file1);
|
||||
$destMd5 = md5_file($file2);
|
||||
|
||||
return $sourceMd5 === $destMd5;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static function tryToCopyFileAndVerifyItWasCopied($source, $dest)
|
||||
{
|
||||
if (!@copy($source, $dest)) {
|
||||
@chmod($dest, 0755);
|
||||
if (!@copy($source, $dest)) {
|
||||
$message = "Error while creating/copying file to <code>$dest</code>. <br />"
|
||||
. Filechecks::getErrorMessageMissingPermissions(self::getPathToPiwikRoot());
|
||||
throw new Exception($message);
|
||||
}
|
||||
}
|
||||
|
||||
if (file_exists($source) && file_exists($dest)) {
|
||||
return self::havePhpFilesSameContent($source, $dest);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue