update Piwik to version 2.16 (fixes #91)

This commit is contained in:
oliver 2016-04-10 18:55:57 +02:00
commit d885a4baa9
5833 changed files with 418860 additions and 226988 deletions

View file

@ -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;
}
}