1<?php
2/*
3 * This file is part of PHPUnit.
4 *
5 * (c) Sebastian Bergmann <sebastian@phpunit.de>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10
11class PHPUnit_Util_GlobalState
12{
13    /**
14     * @var array
15     */
16    protected static $superGlobalArrays = [
17      '_ENV',
18      '_POST',
19      '_GET',
20      '_COOKIE',
21      '_SERVER',
22      '_FILES',
23      '_REQUEST'
24    ];
25
26    /**
27     * @var array
28     */
29    protected static $superGlobalArraysLong = [
30      'HTTP_ENV_VARS',
31      'HTTP_POST_VARS',
32      'HTTP_GET_VARS',
33      'HTTP_COOKIE_VARS',
34      'HTTP_SERVER_VARS',
35      'HTTP_POST_FILES'
36    ];
37
38    /**
39     * @return string
40     */
41    public static function getIncludedFilesAsString()
42    {
43        return static::processIncludedFilesAsString(get_included_files());
44    }
45
46    /**
47     * @param array $files
48     *
49     * @return string
50     */
51    public static function processIncludedFilesAsString(array $files)
52    {
53        $blacklist = new PHPUnit_Util_Blacklist;
54        $prefix    = false;
55        $result    = '';
56
57        if (defined('__PHPUNIT_PHAR__')) {
58            $prefix = 'phar://' . __PHPUNIT_PHAR__ . '/';
59        }
60
61        for ($i = count($files) - 1; $i > 0; $i--) {
62            $file = $files[$i];
63
64            if ($prefix !== false && strpos($file, $prefix) === 0) {
65                continue;
66            }
67
68            // Skip virtual file system protocols
69            if (preg_match('/^(vfs|phpvfs[a-z0-9]+):/', $file)) {
70                continue;
71            }
72
73            if (!$blacklist->isBlacklisted($file) && is_file($file)) {
74                $result = 'require_once \'' . $file . "';\n" . $result;
75            }
76        }
77
78        return $result;
79    }
80
81    /**
82     * @return string
83     */
84    public static function getIniSettingsAsString()
85    {
86        $result      = '';
87        $iniSettings = ini_get_all(null, false);
88
89        foreach ($iniSettings as $key => $value) {
90            $result .= sprintf(
91                '@ini_set(%s, %s);' . "\n",
92                self::exportVariable($key),
93                self::exportVariable($value)
94            );
95        }
96
97        return $result;
98    }
99
100    /**
101     * @return string
102     */
103    public static function getConstantsAsString()
104    {
105        $constants = get_defined_constants(true);
106        $result    = '';
107
108        if (isset($constants['user'])) {
109            foreach ($constants['user'] as $name => $value) {
110                $result .= sprintf(
111                    'if (!defined(\'%s\')) define(\'%s\', %s);' . "\n",
112                    $name,
113                    $name,
114                    self::exportVariable($value)
115                );
116            }
117        }
118
119        return $result;
120    }
121
122    /**
123     * @return string
124     */
125    public static function getGlobalsAsString()
126    {
127        $result            = '';
128        $superGlobalArrays = self::getSuperGlobalArrays();
129
130        foreach ($superGlobalArrays as $superGlobalArray) {
131            if (isset($GLOBALS[$superGlobalArray]) &&
132                is_array($GLOBALS[$superGlobalArray])) {
133                foreach (array_keys($GLOBALS[$superGlobalArray]) as $key) {
134                    if ($GLOBALS[$superGlobalArray][$key] instanceof Closure) {
135                        continue;
136                    }
137
138                    $result .= sprintf(
139                        '$GLOBALS[\'%s\'][\'%s\'] = %s;' . "\n",
140                        $superGlobalArray,
141                        $key,
142                        self::exportVariable($GLOBALS[$superGlobalArray][$key])
143                    );
144                }
145            }
146        }
147
148        $blacklist   = $superGlobalArrays;
149        $blacklist[] = 'GLOBALS';
150
151        foreach (array_keys($GLOBALS) as $key) {
152            if (!in_array($key, $blacklist) && !$GLOBALS[$key] instanceof Closure) {
153                $result .= sprintf(
154                    '$GLOBALS[\'%s\'] = %s;' . "\n",
155                    $key,
156                    self::exportVariable($GLOBALS[$key])
157                );
158            }
159        }
160
161        return $result;
162    }
163
164    /**
165     * @return array
166     */
167    protected static function getSuperGlobalArrays()
168    {
169        if (ini_get('register_long_arrays') == '1') {
170            return array_merge(
171                self::$superGlobalArrays,
172                self::$superGlobalArraysLong
173            );
174        } else {
175            return self::$superGlobalArrays;
176        }
177    }
178
179    protected static function exportVariable($variable)
180    {
181        if (is_scalar($variable) || is_null($variable) ||
182           (is_array($variable) && self::arrayOnlyContainsScalars($variable))) {
183            return var_export($variable, true);
184        }
185
186        return 'unserialize(' .
187                var_export(serialize($variable), true) .
188                ')';
189    }
190
191    /**
192     * @param array $array
193     *
194     * @return bool
195     */
196    protected static function arrayOnlyContainsScalars(array $array)
197    {
198        $result = true;
199
200        foreach ($array as $element) {
201            if (is_array($element)) {
202                $result = self::arrayOnlyContainsScalars($element);
203            } elseif (!is_scalar($element) && !is_null($element)) {
204                $result = false;
205            }
206
207            if ($result === false) {
208                break;
209            }
210        }
211
212        return $result;
213    }
214}
215