PDF rausgenommen
This commit is contained in:
101
msd2/tracking/piwik/core/CliMulti/CliPhp.php
Normal file
101
msd2/tracking/piwik/core/CliMulti/CliPhp.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
/**
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
namespace Piwik\CliMulti;
|
||||
|
||||
use Piwik\Common;
|
||||
|
||||
class CliPhp
|
||||
{
|
||||
|
||||
public function findPhpBinary()
|
||||
{
|
||||
if (defined('PHP_BINARY')) {
|
||||
if ($this->isHhvmBinary(PHP_BINARY)) {
|
||||
return PHP_BINARY . ' --php';
|
||||
}
|
||||
|
||||
if ($this->isValidPhpType(PHP_BINARY)) {
|
||||
return PHP_BINARY . ' -q';
|
||||
}
|
||||
}
|
||||
|
||||
$bin = '';
|
||||
|
||||
if (!empty($_SERVER['_']) && Common::isPhpCliMode()) {
|
||||
$bin = $this->getPhpCommandIfValid($_SERVER['_']);
|
||||
}
|
||||
|
||||
if (empty($bin) && !empty($_SERVER['argv'][0]) && Common::isPhpCliMode()) {
|
||||
$bin = $this->getPhpCommandIfValid($_SERVER['argv'][0]);
|
||||
}
|
||||
|
||||
if (!$this->isValidPhpType($bin)) {
|
||||
$bin = shell_exec('which php');
|
||||
}
|
||||
|
||||
if (!$this->isValidPhpType($bin)) {
|
||||
$bin = shell_exec('which php5');
|
||||
}
|
||||
|
||||
if (!$this->isValidPhpType($bin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$bin = trim($bin);
|
||||
|
||||
if (!$this->isValidPhpVersion($bin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$bin .= ' -q';
|
||||
|
||||
return $bin;
|
||||
}
|
||||
|
||||
private function isHhvmBinary($bin)
|
||||
{
|
||||
return false !== strpos($bin, 'hhvm');
|
||||
}
|
||||
|
||||
private function isValidPhpVersion($bin)
|
||||
{
|
||||
global $piwik_minimumPHPVersion;
|
||||
$cliVersion = $this->getPhpVersion($bin);
|
||||
$isCliVersionValid = version_compare($piwik_minimumPHPVersion, $cliVersion) <= 0;
|
||||
return $isCliVersionValid;
|
||||
}
|
||||
|
||||
private function isValidPhpType($path)
|
||||
{
|
||||
return !empty($path)
|
||||
&& false === strpos($path, 'fpm')
|
||||
&& false === strpos($path, 'cgi')
|
||||
&& false === strpos($path, 'phpunit');
|
||||
}
|
||||
|
||||
private function getPhpCommandIfValid($path)
|
||||
{
|
||||
if (!empty($path) && is_executable($path)) {
|
||||
if (0 === strpos($path, PHP_BINDIR) && $this->isValidPhpType($path)) {
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $bin PHP binary
|
||||
* @return string
|
||||
*/
|
||||
private function getPhpVersion($bin)
|
||||
{
|
||||
$command = sprintf("%s -r 'echo phpversion();'", $bin);
|
||||
$version = shell_exec($command);
|
||||
return $version;
|
||||
}
|
||||
}
|
68
msd2/tracking/piwik/core/CliMulti/Output.php
Normal file
68
msd2/tracking/piwik/core/CliMulti/Output.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/**
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
namespace Piwik\CliMulti;
|
||||
|
||||
use Piwik\CliMulti;
|
||||
use Piwik\Filesystem;
|
||||
|
||||
class Output
|
||||
{
|
||||
|
||||
private $tmpFile = '';
|
||||
private $outputId = null;
|
||||
|
||||
public function __construct($outputId)
|
||||
{
|
||||
if (!Filesystem::isValidFilename($outputId)) {
|
||||
throw new \Exception('The given output id has an invalid format');
|
||||
}
|
||||
|
||||
$dir = CliMulti::getTmpPath();
|
||||
Filesystem::mkdir($dir);
|
||||
|
||||
$this->tmpFile = $dir . '/' . $outputId . '.output';
|
||||
$this->outputId = $outputId;
|
||||
}
|
||||
|
||||
public function getOutputId()
|
||||
{
|
||||
return $this->outputId;
|
||||
}
|
||||
|
||||
public function write($content)
|
||||
{
|
||||
file_put_contents($this->tmpFile, $content);
|
||||
}
|
||||
|
||||
public function getPathToFile()
|
||||
{
|
||||
return $this->tmpFile;
|
||||
}
|
||||
|
||||
public function isAbnormal()
|
||||
{
|
||||
$size = Filesystem::getFileSize($this->tmpFile, 'MB');
|
||||
|
||||
return $size !== null && $size >= 100;
|
||||
}
|
||||
|
||||
public function exists()
|
||||
{
|
||||
return file_exists($this->tmpFile);
|
||||
}
|
||||
|
||||
public function get()
|
||||
{
|
||||
return @file_get_contents($this->tmpFile);
|
||||
}
|
||||
|
||||
public function destroy()
|
||||
{
|
||||
Filesystem::deleteFileIfExists($this->tmpFile);
|
||||
}
|
||||
}
|
266
msd2/tracking/piwik/core/CliMulti/Process.php
Normal file
266
msd2/tracking/piwik/core/CliMulti/Process.php
Normal file
@ -0,0 +1,266 @@
|
||||
<?php
|
||||
/**
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
namespace Piwik\CliMulti;
|
||||
|
||||
use Piwik\CliMulti;
|
||||
use Piwik\Filesystem;
|
||||
use Piwik\SettingsServer;
|
||||
|
||||
/**
|
||||
* There are three different states
|
||||
* - PID file exists with empty content: Process is created but not started
|
||||
* - PID file exists with the actual process PID as content: Process is running
|
||||
* - PID file does not exist: Process is marked as finished
|
||||
*
|
||||
* Class Process
|
||||
*/
|
||||
class Process
|
||||
{
|
||||
private $pidFile = '';
|
||||
private $timeCreation = null;
|
||||
private $isSupported = null;
|
||||
private $pid = null;
|
||||
|
||||
public function __construct($pid)
|
||||
{
|
||||
if (!Filesystem::isValidFilename($pid)) {
|
||||
throw new \Exception('The given pid has an invalid format');
|
||||
}
|
||||
|
||||
$pidDir = CliMulti::getTmpPath();
|
||||
Filesystem::mkdir($pidDir);
|
||||
|
||||
$this->isSupported = self::isSupported();
|
||||
$this->pidFile = $pidDir . '/' . $pid . '.pid';
|
||||
$this->timeCreation = time();
|
||||
$this->pid = $pid;
|
||||
|
||||
$this->markAsNotStarted();
|
||||
}
|
||||
|
||||
public function getPid()
|
||||
{
|
||||
return $this->pid;
|
||||
}
|
||||
|
||||
private function markAsNotStarted()
|
||||
{
|
||||
$content = $this->getPidFileContent();
|
||||
|
||||
if ($this->doesPidFileExist($content)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->writePidFileContent('');
|
||||
}
|
||||
|
||||
public function hasStarted($content = null)
|
||||
{
|
||||
if (is_null($content)) {
|
||||
$content = $this->getPidFileContent();
|
||||
}
|
||||
|
||||
if (!$this->doesPidFileExist($content)) {
|
||||
// process is finished, this means there was a start before
|
||||
return true;
|
||||
}
|
||||
|
||||
if ('' === trim($content)) {
|
||||
// pid file is overwritten by startProcess()
|
||||
return false;
|
||||
}
|
||||
|
||||
// process is probably running or pid file was not removed
|
||||
return true;
|
||||
}
|
||||
|
||||
public function hasFinished()
|
||||
{
|
||||
$content = $this->getPidFileContent();
|
||||
|
||||
return !$this->doesPidFileExist($content);
|
||||
}
|
||||
|
||||
public function getSecondsSinceCreation()
|
||||
{
|
||||
return time() - $this->timeCreation;
|
||||
}
|
||||
|
||||
public function startProcess()
|
||||
{
|
||||
$this->writePidFileContent(getmypid());
|
||||
}
|
||||
|
||||
public function isRunning()
|
||||
{
|
||||
$content = $this->getPidFileContent();
|
||||
|
||||
if (!$this->doesPidFileExist($content)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->pidFileSizeIsNormal()) {
|
||||
$this->finishProcess();
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->isProcessStillRunning($content)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->hasStarted($content)) {
|
||||
$this->finishProcess();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function pidFileSizeIsNormal()
|
||||
{
|
||||
$size = Filesystem::getFileSize($this->pidFile);
|
||||
|
||||
return $size !== null && $size < 500;
|
||||
}
|
||||
|
||||
public function finishProcess()
|
||||
{
|
||||
Filesystem::deleteFileIfExists($this->pidFile);
|
||||
}
|
||||
|
||||
private function doesPidFileExist($content)
|
||||
{
|
||||
return false !== $content;
|
||||
}
|
||||
|
||||
private function isProcessStillRunning($content)
|
||||
{
|
||||
if (!$this->isSupported) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$lockedPID = trim($content);
|
||||
$runningPIDs = self::getRunningProcesses();
|
||||
|
||||
return !empty($lockedPID) && in_array($lockedPID, $runningPIDs);
|
||||
}
|
||||
|
||||
private function getPidFileContent()
|
||||
{
|
||||
return @file_get_contents($this->pidFile);
|
||||
}
|
||||
|
||||
private function writePidFileContent($content)
|
||||
{
|
||||
file_put_contents($this->pidFile, $content);
|
||||
}
|
||||
|
||||
public static function isSupported()
|
||||
{
|
||||
if (SettingsServer::isWindows()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (self::shellExecFunctionIsDisabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (self::isSystemNotSupported()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!self::commandExists('ps') || !self::returnsSuccessCode('ps') || !self::commandExists('awk')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!in_array(getmypid(), self::getRunningProcesses())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!self::isProcFSMounted()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static function isSystemNotSupported()
|
||||
{
|
||||
$uname = @shell_exec('uname -a 2> /dev/null');
|
||||
|
||||
if (empty($uname)) {
|
||||
$uname = php_uname();
|
||||
}
|
||||
|
||||
if (strpos($uname, 'synology') !== false) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static function shellExecFunctionIsDisabled()
|
||||
{
|
||||
$command = 'shell_exec';
|
||||
$disabled = explode(',', ini_get('disable_functions'));
|
||||
$disabled = array_map('trim', $disabled);
|
||||
return in_array($command, $disabled) || !function_exists($command);
|
||||
}
|
||||
|
||||
private static function returnsSuccessCode($command)
|
||||
{
|
||||
$exec = $command . ' > /dev/null 2>&1; echo $?';
|
||||
$returnCode = shell_exec($exec);
|
||||
$returnCode = trim($returnCode);
|
||||
return 0 == (int) $returnCode;
|
||||
}
|
||||
|
||||
private static function commandExists($command)
|
||||
{
|
||||
$result = @shell_exec('which ' . escapeshellarg($command) . ' 2> /dev/null');
|
||||
|
||||
return !empty($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* ps -e requires /proc
|
||||
* @return bool
|
||||
*/
|
||||
private static function isProcFSMounted()
|
||||
{
|
||||
if (is_resource(@fopen('/proc', 'r'))) {
|
||||
return true;
|
||||
}
|
||||
// Testing if /proc is a resource with @fopen fails on systems with open_basedir set.
|
||||
// by using stat we not only test the existence of /proc but also confirm it's a 'proc' filesystem
|
||||
$type = @shell_exec('stat -f -c "%T" /proc 2>/dev/null');
|
||||
return strpos($type, 'proc') === 0;
|
||||
}
|
||||
|
||||
public static function getListOfRunningProcesses()
|
||||
{
|
||||
$processes = `ps ex 2>/dev/null`;
|
||||
if (empty($processes)) {
|
||||
return array();
|
||||
}
|
||||
return explode("\n", $processes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int[] The ids of the currently running processes
|
||||
*/
|
||||
public static function getRunningProcesses()
|
||||
{
|
||||
$ids = explode("\n", trim(`ps ex 2>/dev/null | awk '! /defunct/ {print $1}' 2>/dev/null`));
|
||||
|
||||
$ids = array_map('intval', $ids);
|
||||
$ids = array_filter($ids, function ($id) {
|
||||
return $id > 0;
|
||||
});
|
||||
|
||||
return $ids;
|
||||
}
|
||||
}
|
129
msd2/tracking/piwik/core/CliMulti/RequestCommand.php
Normal file
129
msd2/tracking/piwik/core/CliMulti/RequestCommand.php
Normal file
@ -0,0 +1,129 @@
|
||||
<?php
|
||||
/**
|
||||
* Piwik - free/libre analytics platform
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace Piwik\CliMulti;
|
||||
|
||||
use Piwik\Application\Environment;
|
||||
use Piwik\Access;
|
||||
use Piwik\Container\StaticContainer;
|
||||
use Piwik\Db;
|
||||
use Piwik\Log;
|
||||
use Piwik\Option;
|
||||
use Piwik\Plugin\ConsoleCommand;
|
||||
use Piwik\Url;
|
||||
use Piwik\UrlHelper;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* RequestCommand
|
||||
*/
|
||||
class RequestCommand extends ConsoleCommand
|
||||
{
|
||||
/**
|
||||
* @var Environment
|
||||
*/
|
||||
private $environment;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('climulti:request');
|
||||
$this->setDescription('Parses and executes the given query. See Piwik\CliMulti. Intended only for system usage.');
|
||||
$this->addArgument('url-query', InputArgument::REQUIRED, 'Matomo URL query string, for instance: "module=API&method=API.getPiwikVersion&token_auth=123456789"');
|
||||
$this->addOption('superuser', null, InputOption::VALUE_NONE, 'If supplied, runs the code as superuser.');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->recreateContainerWithWebEnvironment();
|
||||
|
||||
$this->initHostAndQueryString($input);
|
||||
|
||||
if ($this->isTestModeEnabled()) {
|
||||
$indexFile = '/tests/PHPUnit/proxy/';
|
||||
|
||||
$this->resetDatabase();
|
||||
} else {
|
||||
$indexFile = '/';
|
||||
}
|
||||
|
||||
$indexFile .= 'index.php';
|
||||
|
||||
if (!empty($_GET['pid'])) {
|
||||
$process = new Process($_GET['pid']);
|
||||
|
||||
if ($process->hasFinished()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$process->startProcess();
|
||||
}
|
||||
|
||||
if ($input->getOption('superuser')) {
|
||||
StaticContainer::addDefinitions(array(
|
||||
'observers.global' => \DI\add(array(
|
||||
array('Environment.bootstrapped', function () {
|
||||
Access::getInstance()->setSuperUserAccess(true);
|
||||
})
|
||||
)),
|
||||
));
|
||||
}
|
||||
|
||||
require_once PIWIK_INCLUDE_PATH . $indexFile;
|
||||
|
||||
if (!empty($process)) {
|
||||
$process->finishProcess();
|
||||
}
|
||||
}
|
||||
|
||||
private function isTestModeEnabled()
|
||||
{
|
||||
return !empty($_GET['testmode']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
*/
|
||||
protected function initHostAndQueryString(InputInterface $input)
|
||||
{
|
||||
$_GET = array();
|
||||
|
||||
// @todo remove piwik-domain fallback in Matomo 4
|
||||
$hostname = $input->getOption('matomo-domain') ?: $input->getOption('piwik-domain');
|
||||
Url::setHost($hostname);
|
||||
|
||||
$query = $input->getArgument('url-query');
|
||||
$query = UrlHelper::getArrayFromQueryString($query); // NOTE: this method can create the StaticContainer now
|
||||
foreach ($query as $name => $value) {
|
||||
$_GET[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We will be simulating an HTTP request here (by including index.php).
|
||||
*
|
||||
* To avoid weird side-effects (e.g. the logging output messing up the HTTP response on the CLI output)
|
||||
* we need to recreate the container with the default environment instead of the CLI environment.
|
||||
*/
|
||||
private function recreateContainerWithWebEnvironment()
|
||||
{
|
||||
StaticContainer::clearContainer();
|
||||
Log::unsetInstance();
|
||||
|
||||
$this->environment = new Environment(null);
|
||||
$this->environment->init();
|
||||
}
|
||||
|
||||
private function resetDatabase()
|
||||
{
|
||||
Option::clearCache();
|
||||
Db::destroyDatabaseObject();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user