1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Fwk - Another micro PHP 5 framework |
4
|
|
|
* |
5
|
|
|
* @author Mathieu LESNIAK <[email protected]> |
6
|
|
|
* @copyright 2013-2014 Mathieu LESNIAK |
7
|
|
|
* @version 0.1 |
8
|
|
|
* @package Suricate |
9
|
|
|
* |
10
|
|
|
* @method App App() App() Get instance of App service |
11
|
|
|
* @method Database Database() Database() Get instance of Database service |
12
|
|
|
* @method Error Error() Error() Get instance of Error service |
13
|
|
|
* @method I18n I18n() I18n() Get instance of I18n service |
14
|
|
|
* @method Request Request() Request() Get instance of Request service |
15
|
|
|
*/ |
16
|
|
|
namespace Suricate; |
17
|
|
|
|
18
|
|
|
class Suricate |
19
|
|
|
{ |
20
|
|
|
|
21
|
|
|
const VERSION = '0.1'; |
22
|
|
|
|
23
|
|
|
const CONF_DIR = '/conf/'; |
24
|
|
|
|
25
|
|
|
protected $router; |
26
|
|
|
|
27
|
|
|
private $config; |
28
|
|
|
private $configFile; |
29
|
|
|
|
30
|
|
|
private $useAutoloader = false; |
31
|
|
|
|
32
|
|
|
private static $servicesContainer; |
33
|
|
|
private static $servicesRepository; |
34
|
|
|
|
35
|
|
|
private $servicesList = array( |
36
|
|
|
'Logger' => '\Suricate\Logger', |
37
|
|
|
'App' => '\Suricate\App', |
38
|
|
|
'I18n' => '\Suricate\I18n', |
39
|
|
|
'Error' => '\Suricate\Error', |
40
|
|
|
'Router' => '\Suricate\Router', |
41
|
|
|
'Request' => '\Suricate\Request', |
42
|
|
|
'Database' => '\Suricate\Database', |
43
|
|
|
'Cache' => '\Suricate\Cache', |
44
|
|
|
'CacheMemcache' => '\Suricate\Cache\Memcache', |
45
|
|
|
'CacheApc' => '\Suricate\Cache\Apc', |
46
|
|
|
'Curl' => '\Suricate\Curl', |
47
|
|
|
'Response' => '\Suricate\Request', |
48
|
|
|
'Session' => '\Suricate\Session', |
49
|
|
|
'SessionNative' => '\Suricate\Session\Native', |
50
|
|
|
'SessionCookie' => '\Suricate\Session\Cookie', |
51
|
|
|
'SessionMemcache' => '\Suricate\Session\Memcache', |
52
|
|
|
); |
53
|
|
|
|
54
|
|
|
|
55
|
|
|
public function __construct($paths = array(), $configFile = null) |
56
|
|
|
{ |
57
|
|
|
if ($configFile !== null) { |
58
|
|
|
$this->setConfigFile($configFile); |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
// Load helpers |
62
|
|
|
require_once __DIR__ . DIRECTORY_SEPARATOR . 'Helper.php'; |
63
|
|
|
|
64
|
|
|
$this->loadConfig(); |
65
|
|
|
$this->setAppPaths($paths); |
66
|
|
|
|
67
|
|
|
if ($this->useAutoloader) { |
68
|
|
|
// Configure autoloader |
69
|
|
|
require_once __DIR__ . DIRECTORY_SEPARATOR . 'AutoLoader.php'; |
70
|
|
|
AutoLoader::register(); |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
// Define error handler |
74
|
|
|
set_exception_handler(array('\Suricate\Error', 'handleException')); |
75
|
|
|
set_error_handler(array('\Suricate\Error', 'handleError')); |
76
|
|
|
register_shutdown_function(array('\Suricate\Error', 'handleShutdownError')); |
77
|
|
|
|
78
|
|
|
self::$servicesRepository = new Container(); |
79
|
|
|
|
80
|
|
|
$this->initServices(); |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
private function setAppPaths($paths = array()) |
84
|
|
|
{ |
85
|
|
|
foreach ($paths as $key=>$value) { |
86
|
|
|
$this->config['App']['path.' . $key] = realpath($value); |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
return $this; |
90
|
|
|
} |
91
|
|
|
/** |
92
|
|
|
* Initialize Framework services |
93
|
|
|
* @return null |
94
|
|
|
*/ |
95
|
|
|
private function initServices() |
96
|
|
|
{ |
97
|
|
|
self::$servicesRepository->setWarehouse($this->servicesList); |
98
|
|
|
|
99
|
|
|
self::$servicesRepository['Request']->parse(); |
100
|
|
|
if (isset($this->config['App']['locale'])) { |
101
|
|
|
$this->config['I18n'] = array('locale' => $this->config['App']['locale']); |
102
|
|
|
} |
103
|
|
|
// first sync, && init, dependency to Suricate::request |
104
|
|
|
self::$servicesContainer = clone self::$servicesRepository; |
105
|
|
|
|
106
|
|
|
foreach (array_keys($this->servicesList) as $serviceName) { |
107
|
|
|
if (isset($this->config[$serviceName])) { |
108
|
|
|
self::$servicesRepository[$serviceName]->configure($this->config[$serviceName]); |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
TODO : remove sync in service creation |
112
|
|
|
*/ |
113
|
|
|
self::$servicesContainer = clone self::$servicesRepository; |
114
|
|
|
} |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
if (isset($this->config['Constants'])) { |
118
|
|
|
foreach ($this->config['Constants'] as $constantName => $constantValue) { |
119
|
|
|
$constantName = strtoupper($constantName); |
120
|
|
|
define($constantName, $constantValue); |
121
|
|
|
} |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
// final sync, repository is complete |
125
|
|
|
self::$servicesContainer = clone self::$servicesRepository; |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
private function setConfigFile($configFile) |
129
|
|
|
{ |
130
|
|
|
foreach ((array) $configFile as $file) { |
131
|
|
|
if (is_file($file)) { |
132
|
|
|
$this->configFile[] = $file; |
133
|
|
|
} |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
|
137
|
|
|
|
138
|
|
|
return $this; |
139
|
|
|
} |
140
|
|
|
/** |
141
|
|
|
* Load framework configuration from ini file |
142
|
|
|
* @return null |
143
|
|
|
*/ |
144
|
|
|
private function loadConfig() |
145
|
|
|
{ |
146
|
|
|
$userConfig = array(); |
147
|
|
|
if ($this->configFile !== null) { |
148
|
|
|
$userConfig = array(); |
149
|
|
|
foreach ($this->configFile as $configFile) { |
150
|
|
|
$userConfig = array_merge($userConfig, parse_ini_file($configFile, true)); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
// Advanced ini parsing, split key with '.' into subarrays |
154
|
|
|
foreach ($userConfig as $section => $configData) { |
155
|
|
|
foreach ($configData as $name => $value) { |
156
|
|
|
if (stripos($name, '.') !== false) { |
157
|
|
|
$subkeys = explode('.', $name); |
158
|
|
|
unset($userConfig[$section][$name]); |
159
|
|
|
$str = "['" . implode("']['", $subkeys) . "'] = \$value;"; |
160
|
|
|
eval("\$userConfig[\$section]" . $str); |
|
|
|
|
161
|
|
|
} |
162
|
|
|
} |
163
|
|
|
} |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
foreach ($this->getDefaultConfig() as $context => $directives) { |
167
|
|
|
if (isset($userConfig[$context])) { |
168
|
|
|
$this->config[$context] = array_merge($directives, $userConfig[$context]); |
169
|
|
|
unset($userConfig[$context]); |
170
|
|
|
} else { |
171
|
|
|
$this->config[$context] = $directives; |
172
|
|
|
} |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
$this->config = array_merge($this->config, $userConfig); |
176
|
|
|
|
177
|
|
|
$this->configureAppMode(); |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
private function configureAppMode() |
181
|
|
|
{ |
182
|
|
|
$errorReporting = false; |
183
|
|
|
$errorDumpContext = false; |
184
|
|
|
$logLevel = Logger::LOGLEVEL_WARN; |
185
|
|
|
|
186
|
|
|
if (isset($this->config['App']['mode'])) { |
187
|
|
|
switch ($this->config['App']['mode']) { |
188
|
|
View Code Duplication |
case App::DEVELOPMENT_MODE: |
|
|
|
|
189
|
|
|
$errorReporting = true; |
190
|
|
|
$errorDumpContext = true; |
191
|
|
|
$logLevel = Logger::LOGLEVEL_INFO; |
192
|
|
|
break; |
193
|
|
View Code Duplication |
case App::DEBUG_MODE: |
|
|
|
|
194
|
|
|
$errorReporting = true; |
195
|
|
|
$errorDumpContext = true; |
196
|
|
|
$logLevel = Logger::LOGLEVEL_DEBUG; |
197
|
|
|
break; |
198
|
|
View Code Duplication |
case App::PRELIVE_MODE: |
|
|
|
|
199
|
|
|
$errorReporting = true; |
200
|
|
|
$errorDumpContext = false; |
201
|
|
|
$logLevel = Logger::LOGLEVEL_WARN; |
202
|
|
|
break; |
203
|
|
View Code Duplication |
case App::PRODUCTION_MODE: |
|
|
|
|
204
|
|
|
$errorReporting = false; |
205
|
|
|
$errorDumpContext = false; |
206
|
|
|
$logLevel = Logger::LOGLEVEL_WARN; |
207
|
|
|
break; |
208
|
|
|
} |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
$this->config['Error']['report'] = $errorReporting; |
212
|
|
|
$this->config['Error']['dumpContext'] = $errorDumpContext; |
213
|
|
|
$this->config['Logger']['level'] = $logLevel; |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
/** |
217
|
|
|
* Default setup template |
218
|
|
|
* @return array setup |
219
|
|
|
*/ |
220
|
|
|
private function getDefaultConfig() |
221
|
|
|
{ |
222
|
|
|
return array( |
223
|
|
|
'Router' => array(), |
224
|
|
|
'Session' => array('type' => 'native'), |
225
|
|
|
'Logger' => array( |
226
|
|
|
'logfile' => 'php://output', |
227
|
|
|
'enabled' => true, |
228
|
|
|
'level' => Logger::LOGLEVEL_INFO, |
229
|
|
|
), |
230
|
|
|
'App' => array('base_uri' => '/'), |
231
|
|
|
); |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
public function run() |
235
|
|
|
{ |
236
|
|
|
self::$servicesContainer['Router']->doRouting(); |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
public static function __callStatic($name, $arguments) |
240
|
|
|
{ |
241
|
|
|
if (isset($arguments[0]) && $arguments[0] === true) { |
242
|
|
|
return clone self::$servicesRepository[$name]; |
243
|
|
|
} else { |
244
|
|
|
return self::$servicesContainer[$name]; |
245
|
|
|
} |
246
|
|
|
} |
247
|
|
|
} |
248
|
|
|
|
On one hand,
eval
might be exploited by malicious users if they somehow manage to inject dynamic content. On the other hand, with the emergence of faster PHP runtimes like the HHVM,eval
prevents some optimization that they perform.