1<?php
2/**
3 * Matomo - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 *
8 */
9namespace Piwik;
10
11/**
12 * Contains helper methods that can be used to get information regarding the
13 * server, its settings and currently used PHP settings.
14 *
15 */
16class SettingsServer
17{
18    /**
19     * Returns true if the current script execution was triggered by the cron archiving script.
20     *
21     * Helpful for error handling: directly throw error without HTML (eg. when DB is down).
22     *
23     * @return bool
24     * @api
25     */
26    public static function isArchivePhpTriggered()
27    {
28        return !empty($_GET['trigger'])
29                && $_GET['trigger'] == 'archivephp'
30                && Piwik::hasUserSuperUserAccess();
31    }
32
33    /**
34     * Returns true if the current request is a Tracker request.
35     *
36     * @return bool true if the current request is a Tracking API Request (ie. piwik.php)
37     */
38    public static function isTrackerApiRequest()
39    {
40        return !empty($GLOBALS['PIWIK_TRACKER_MODE']);
41    }
42
43    /**
44     * Mark the current request as a Tracker API request
45     */
46    public static function setIsTrackerApiRequest()
47    {
48        $GLOBALS['PIWIK_TRACKER_MODE'] = true;
49    }
50
51    /**
52     * Set the current request is not a tracker API request
53     */
54    public static function setIsNotTrackerApiRequest()
55    {
56        $GLOBALS['PIWIK_TRACKER_MODE'] = false;
57    }
58
59    /**
60     * Returns true if Matomo is running within Matomo for WordPress.
61     *
62     * @return bool  true if Matomo is running in WordPress, false if Matomo is running as part of On-Premise
63     * @api
64     */
65    public static function isMatomoForWordPress()
66    {
67        return defined( 'ABSPATH') && function_exists('\add_action');
68    }
69
70    /**
71     * Returns `true` if running on Microsoft IIS 7 (or above), `false` if otherwise.
72     *
73     * @return bool
74     * @api
75     */
76    public static function isIIS()
77    {
78        $iis = isset($_SERVER['SERVER_SOFTWARE']) &&
79            preg_match('/^Microsoft-IIS\/(.+)/', $_SERVER['SERVER_SOFTWARE'], $matches) &&
80            version_compare($matches[1], '7') >= 0;
81
82        return $iis;
83    }
84
85    /**
86     * Returns `true` if running on a Windows operating system, `false` if otherwise.
87     *
88     * @since 0.6.5
89     * @return bool
90     * @api
91     */
92    public static function isWindows()
93    {
94        if (PHP_OS_FAMILY == "Unknown") {
95            return DIRECTORY_SEPARATOR === '\\';
96        }
97        return PHP_OS_FAMILY === "Windows";
98    }
99
100    /**
101     * Returns `true` if this PHP version/build supports timezone manipulation
102     * (e.g., php >= 5.2, or compiled with **EXPERIMENTAL_DATE_SUPPORT=1** for
103     * php < 5.2).
104     *
105     * @return bool
106     * @api
107     */
108    public static function isTimezoneSupportEnabled()
109    {
110        return
111            function_exists('date_create') &&
112            function_exists('date_default_timezone_set') &&
113            function_exists('timezone_identifiers_list') &&
114            function_exists('timezone_open') &&
115            function_exists('timezone_offset_get');
116    }
117
118    /**
119     * Returns `true` if the GD PHP extension is available, `false` if otherwise.
120     *
121     * _Note: ImageGraph and the sparkline report visualization depend on the GD extension._
122     *
123     * @return bool
124     * @api
125     */
126    public static function isGdExtensionEnabled()
127    {
128        static $gd = null;
129        if (is_null($gd)) {
130            $gd = false;
131
132            $extensions = @get_loaded_extensions();
133            if (is_array($extensions)) {
134                $gd = in_array('gd', $extensions) && function_exists('imageftbbox');
135            }
136        }
137
138        return $gd;
139    }
140
141    /**
142     * Raise PHP memory limit if below the minimum required
143     *
144     * @return bool  true if set; false otherwise
145     */
146    public static function raiseMemoryLimitIfNecessary()
147    {
148        if (self::isArchivePhpTriggered()) {
149            // core:archive command: no time limit
150            self::setMaxExecutionTime( 0 );
151        }
152
153        $memoryLimit = self::getMemoryLimitValue();
154        if ($memoryLimit === false) {
155            return false;
156        }
157        $minimumMemoryLimit = Config::getInstance()->General['minimum_memory_limit'];
158
159        if (self::isArchivePhpTriggered()) {
160            // core:archive command:  high memory limit
161            $minimumMemoryLimitWhenArchiving = Config::getInstance()->General['minimum_memory_limit_when_archiving'];
162            if ($memoryLimit < $minimumMemoryLimitWhenArchiving) {
163                return self::setMemoryLimit($minimumMemoryLimitWhenArchiving);
164            }
165            return false;
166        }
167        if ($memoryLimit < $minimumMemoryLimit) {
168            return self::setMemoryLimit($minimumMemoryLimit);
169        }
170        return false;
171    }
172
173    /**
174     * Set PHP memory limit
175     *
176     * Note: system settings may prevent scripts from overriding the master value
177     *
178     * @param int $minimumMemoryLimit
179     * @return bool  true if set; false otherwise
180     */
181    protected static function setMemoryLimit($minimumMemoryLimit)
182    {
183        // in Megabytes
184        $currentValue = self::getMemoryLimitValue();
185        if ($currentValue === false
186            || ($currentValue < $minimumMemoryLimit && @ini_set('memory_limit', $minimumMemoryLimit . 'M'))
187        ) {
188            return true;
189        }
190        return false;
191    }
192
193    /**
194     * Get php memory_limit (in Megabytes)
195     *
196     * Prior to PHP 5.2.1, or on Windows, --enable-memory-limit is not a
197     * compile-time default, so ini_get('memory_limit') may return false.
198     *
199     * @return int|bool  memory limit in megabytes, or false if there is no limit
200     */
201    public static function getMemoryLimitValue()
202    {
203        if (($memory = ini_get('memory_limit')) > 0) {
204            return self::getMegaBytesFromShorthandByte($memory);
205        }
206
207        // no memory limit
208        return false;
209    }
210
211    /**
212     * Get php post_max_size (in Megabytes)
213     *
214     * @return int|bool  max upload size in megabytes, or false if there is no limit
215     */
216    public static function getPostMaxUploadSize()
217    {
218        if (($maxPostSize = ini_get('post_max_size')) > 0) {
219            return self::getMegaBytesFromShorthandByte($maxPostSize);
220        }
221
222        // no max upload size
223        return false;
224    }
225
226    /**
227     * @see http://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes
228     * @param $value
229     * @return false|float|int
230     */
231    private static function getMegaBytesFromShorthandByte($value)
232    {
233        $value = str_replace(' ', '', $value);
234
235        $shorthandByteOption = substr($value, -1);
236        switch ($shorthandByteOption) {
237            case 'G':
238            case 'g':
239                return substr($value, 0, -1) * 1024;
240            case 'M':
241            case 'm':
242                return substr($value, 0, -1);
243            case 'K':
244            case 'k':
245                return substr($value, 0, -1) / 1024;
246        }
247
248        if (is_numeric($value)) {
249            return (int) $value / 1048576;
250        }
251
252        return false;
253    }
254
255    /**
256     * Set maximum script execution time.
257     *
258     * @param int $executionTime max execution time in seconds (0 = no limit)
259     */
260    public static function setMaxExecutionTime($executionTime)
261    {
262        // in the event one or the other is disabled...
263        @ini_set('max_execution_time', $executionTime);
264        if (function_exists('set_time_limit')) {
265            @set_time_limit($executionTime);
266        }
267    }
268
269    public static function isMac()
270    {
271        return defined('PHP_OS') && PHP_OS === 'Darwin';
272    }
273}
274