28 |
29 | {% endblock %}
--------------------------------------------------------------------------------
/src/AppBundle/Resources/views/Layout/_navigation.html.twig:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/AppBundle/Resources/views/layout.html.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ page_title is defined ? page_title : 'Purl - Your very own URL shortener!' }}
5 |
6 |
8 |
9 |
10 |
11 | {% include 'AppBundle:Layout:_navigation.html.twig' %}
12 |
13 | {% block body %}{% endblock %}
14 |
15 | {% block javascripts %}
16 |
17 | {% endblock %}
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/AppBundle/Security/ApiKeyAuthenticator.php:
--------------------------------------------------------------------------------
1 | getCredentials();
30 | $username = $userProvider->getUsernameForApiKey($apiKey);
31 |
32 | if (!$username) {
33 | throw new CustomUserMessageAuthenticationException(
34 | sprintf('API Key "%s" does not exist.', $apiKey)
35 | );
36 | }
37 |
38 | $user = $userProvider->loadUserByUsername($username);
39 |
40 | return new PreAuthenticatedToken(
41 | $user,
42 | $apiKey,
43 | $providerKey,
44 | $user->getRoles()
45 | );
46 | }
47 |
48 | public function supportsToken(TokenInterface $token, $providerKey)
49 | {
50 | return $token instanceof PreAuthenticatedToken && $token->getProviderKey() === $providerKey;
51 | }
52 |
53 | public function createToken(Request $request, $providerKey)
54 | {
55 | $apiKey = $request->query->get('apiKey');
56 |
57 | if (!$apiKey) {
58 | throw new BadCredentialsException('No API key found');
59 | }
60 |
61 | return new PreAuthenticatedToken(
62 | 'anon.',
63 | $apiKey,
64 | $providerKey
65 | );
66 | }
67 |
68 | /**
69 | * This is called when an interactive authentication attempt fails. This is
70 | * called by authentication listeners inheriting from
71 | * AbstractAuthenticationListener.
72 | *
73 | * @param Request $request
74 | * @param AuthenticationException $exception
75 | *
76 | * @return Response The response to return, never null
77 | */
78 | public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
79 | {
80 | return new Response(
81 | strtr($exception->getMessageKey(), $exception->getMessageData()),
82 | 403
83 | );
84 | }
85 | }
--------------------------------------------------------------------------------
/src/AppBundle/Security/ApiKeyUserProvider.php:
--------------------------------------------------------------------------------
1 | em = $em;
24 | }
25 |
26 | public function getUsernameForApiKey($apiKey)
27 | {
28 | // Look up the username based on the token in the database, via
29 | // an API call, or do something entirely different
30 | // $username = ...;
31 | $apiKey = $this->em->getRepository('AppBundle:ApiKey')->findOneBy(['apiKey' => $apiKey]);
32 |
33 | if (!$apiKey || !$apiKey->getUser()) {
34 | throw new AccessDeniedException();
35 | }
36 |
37 | return $apiKey->getUser()->getUsername();
38 | }
39 |
40 | public function loadUserByUsername($username)
41 | {
42 | $user = $this->em->getRepository('AppBundle:User')->findOneBy(['username' => $username]);
43 | return $user;
44 | }
45 |
46 | public function refreshUser(UserInterface $user)
47 | {
48 | // this is used for storing authentication in the session
49 | // but in this example, the token is sent in each request,
50 | // so authentication can be stateless. Throwing this exception
51 | // is proper to make things stateless
52 | throw new AccessDeniedException();
53 | }
54 |
55 | public function supportsClass($class)
56 | {
57 | return 'Symfony\Component\Security\Core\User\User' === $class;
58 | }
59 | }
--------------------------------------------------------------------------------
/src/AppBundle/Service/CodeGeneratorService.php:
--------------------------------------------------------------------------------
1 | salt = $salt;
18 | }
19 |
20 | public function generateCode()
21 | {
22 | $hashIds = new Hashids($this->salt);
23 | return $hashIds->encode(time() - 1000000000);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/tests/AppBundle/Controller/LinksControllerTest.php:
--------------------------------------------------------------------------------
1 | client = static::createClient();
15 | $this->loadFixtures([
16 | 'AppBundle\DataFixtures\ORM\LoadUserData',
17 | 'AppBundle\DataFixtures\ORM\LoadApiKeyData',
18 | 'AppBundle\DataFixtures\ORM\LoadLinkData',
19 | ]);
20 | }
21 |
22 | protected function assertJsonResponse($response, $statusCode = 200)
23 | {
24 | $this->assertEquals(
25 | $statusCode, $response->getStatusCode(),
26 | $response->getContent()
27 | );
28 | $this->assertTrue(
29 | $response->headers->contains('Content-Type', 'application/json'),
30 | $response->headers
31 | );
32 | }
33 |
34 | public function testGetLink()
35 | {
36 | $testUrl = sprintf('%s%s', $this->getApiUrl(), '/link/test.json?apiKey=test-key');
37 | $this->client->request('GET', $testUrl, ['ACCEPT' => 'application/json']);
38 |
39 | $response = $this->client->getResponse();
40 |
41 | $this->assertJsonResponse($response, 200);
42 | $this->assertContains('"url":"http:\/\/google.be","code":"test","clicks":0}}', $response->getContent());
43 | }
44 |
45 | public function getApiUrl()
46 | {
47 | return 'http://purl.docker/api/v1';
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/var/SymfonyRequirements.php:
--------------------------------------------------------------------------------
1 |
7 | *
8 | * For the full copyright and license information, please view the LICENSE
9 | * file that was distributed with this source code.
10 | */
11 |
12 | /*
13 | * Users of PHP 5.2 should be able to run the requirements checks.
14 | * This is why the file and all classes must be compatible with PHP 5.2+
15 | * (e.g. not using namespaces and closures).
16 | *
17 | * ************** CAUTION **************
18 | *
19 | * DO NOT EDIT THIS FILE as it will be overridden by Composer as part of
20 | * the installation/update process. The original file resides in the
21 | * SensioDistributionBundle.
22 | *
23 | * ************** CAUTION **************
24 | */
25 |
26 | /**
27 | * Represents a single PHP requirement, e.g. an installed extension.
28 | * It can be a mandatory requirement or an optional recommendation.
29 | * There is a special subclass, named PhpIniRequirement, to check a php.ini configuration.
30 | *
31 | * @author Tobias Schultze
32 | */
33 | class Requirement
34 | {
35 | private $fulfilled;
36 | private $testMessage;
37 | private $helpText;
38 | private $helpHtml;
39 | private $optional;
40 |
41 | /**
42 | * Constructor that initializes the requirement.
43 | *
44 | * @param bool $fulfilled Whether the requirement is fulfilled
45 | * @param string $testMessage The message for testing the requirement
46 | * @param string $helpHtml The help text formatted in HTML for resolving the problem
47 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
48 | * @param bool $optional Whether this is only an optional recommendation not a mandatory requirement
49 | */
50 | public function __construct($fulfilled, $testMessage, $helpHtml, $helpText = null, $optional = false)
51 | {
52 | $this->fulfilled = (bool) $fulfilled;
53 | $this->testMessage = (string) $testMessage;
54 | $this->helpHtml = (string) $helpHtml;
55 | $this->helpText = null === $helpText ? strip_tags($this->helpHtml) : (string) $helpText;
56 | $this->optional = (bool) $optional;
57 | }
58 |
59 | /**
60 | * Returns whether the requirement is fulfilled.
61 | *
62 | * @return bool true if fulfilled, otherwise false
63 | */
64 | public function isFulfilled()
65 | {
66 | return $this->fulfilled;
67 | }
68 |
69 | /**
70 | * Returns the message for testing the requirement.
71 | *
72 | * @return string The test message
73 | */
74 | public function getTestMessage()
75 | {
76 | return $this->testMessage;
77 | }
78 |
79 | /**
80 | * Returns the help text for resolving the problem.
81 | *
82 | * @return string The help text
83 | */
84 | public function getHelpText()
85 | {
86 | return $this->helpText;
87 | }
88 |
89 | /**
90 | * Returns the help text formatted in HTML.
91 | *
92 | * @return string The HTML help
93 | */
94 | public function getHelpHtml()
95 | {
96 | return $this->helpHtml;
97 | }
98 |
99 | /**
100 | * Returns whether this is only an optional recommendation and not a mandatory requirement.
101 | *
102 | * @return bool true if optional, false if mandatory
103 | */
104 | public function isOptional()
105 | {
106 | return $this->optional;
107 | }
108 | }
109 |
110 | /**
111 | * Represents a PHP requirement in form of a php.ini configuration.
112 | *
113 | * @author Tobias Schultze
114 | */
115 | class PhpIniRequirement extends Requirement
116 | {
117 | /**
118 | * Constructor that initializes the requirement.
119 | *
120 | * @param string $cfgName The configuration name used for ini_get()
121 | * @param bool|callback $evaluation Either a boolean indicating whether the configuration should evaluate to true or false,
122 | * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
123 | * @param bool $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
124 | * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
125 | * Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
126 | * @param string|null $testMessage The message for testing the requirement (when null and $evaluation is a boolean a default message is derived)
127 | * @param string|null $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a boolean a default help is derived)
128 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
129 | * @param bool $optional Whether this is only an optional recommendation not a mandatory requirement
130 | */
131 | public function __construct($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null, $optional = false)
132 | {
133 | $cfgValue = ini_get($cfgName);
134 |
135 | if (is_callable($evaluation)) {
136 | if (null === $testMessage || null === $helpHtml) {
137 | throw new InvalidArgumentException('You must provide the parameters testMessage and helpHtml for a callback evaluation.');
138 | }
139 |
140 | $fulfilled = call_user_func($evaluation, $cfgValue);
141 | } else {
142 | if (null === $testMessage) {
143 | $testMessage = sprintf('%s %s be %s in php.ini',
144 | $cfgName,
145 | $optional ? 'should' : 'must',
146 | $evaluation ? 'enabled' : 'disabled'
147 | );
148 | }
149 |
150 | if (null === $helpHtml) {
151 | $helpHtml = sprintf('Set %s to %s in php.ini*.',
152 | $cfgName,
153 | $evaluation ? 'on' : 'off'
154 | );
155 | }
156 |
157 | $fulfilled = $evaluation == $cfgValue;
158 | }
159 |
160 | parent::__construct($fulfilled || ($approveCfgAbsence && false === $cfgValue), $testMessage, $helpHtml, $helpText, $optional);
161 | }
162 | }
163 |
164 | /**
165 | * A RequirementCollection represents a set of Requirement instances.
166 | *
167 | * @author Tobias Schultze
168 | */
169 | class RequirementCollection implements IteratorAggregate
170 | {
171 | /**
172 | * @var Requirement[]
173 | */
174 | private $requirements = array();
175 |
176 | /**
177 | * Gets the current RequirementCollection as an Iterator.
178 | *
179 | * @return Traversable A Traversable interface
180 | */
181 | public function getIterator()
182 | {
183 | return new ArrayIterator($this->requirements);
184 | }
185 |
186 | /**
187 | * Adds a Requirement.
188 | *
189 | * @param Requirement $requirement A Requirement instance
190 | */
191 | public function add(Requirement $requirement)
192 | {
193 | $this->requirements[] = $requirement;
194 | }
195 |
196 | /**
197 | * Adds a mandatory requirement.
198 | *
199 | * @param bool $fulfilled Whether the requirement is fulfilled
200 | * @param string $testMessage The message for testing the requirement
201 | * @param string $helpHtml The help text formatted in HTML for resolving the problem
202 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
203 | */
204 | public function addRequirement($fulfilled, $testMessage, $helpHtml, $helpText = null)
205 | {
206 | $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, false));
207 | }
208 |
209 | /**
210 | * Adds an optional recommendation.
211 | *
212 | * @param bool $fulfilled Whether the recommendation is fulfilled
213 | * @param string $testMessage The message for testing the recommendation
214 | * @param string $helpHtml The help text formatted in HTML for resolving the problem
215 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
216 | */
217 | public function addRecommendation($fulfilled, $testMessage, $helpHtml, $helpText = null)
218 | {
219 | $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, true));
220 | }
221 |
222 | /**
223 | * Adds a mandatory requirement in form of a php.ini configuration.
224 | *
225 | * @param string $cfgName The configuration name used for ini_get()
226 | * @param bool|callback $evaluation Either a boolean indicating whether the configuration should evaluate to true or false,
227 | * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
228 | * @param bool $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
229 | * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
230 | * Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
231 | * @param string $testMessage The message for testing the requirement (when null and $evaluation is a boolean a default message is derived)
232 | * @param string $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a boolean a default help is derived)
233 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
234 | */
235 | public function addPhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null)
236 | {
237 | $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, false));
238 | }
239 |
240 | /**
241 | * Adds an optional recommendation in form of a php.ini configuration.
242 | *
243 | * @param string $cfgName The configuration name used for ini_get()
244 | * @param bool|callback $evaluation Either a boolean indicating whether the configuration should evaluate to true or false,
245 | * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
246 | * @param bool $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
247 | * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
248 | * Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
249 | * @param string $testMessage The message for testing the requirement (when null and $evaluation is a boolean a default message is derived)
250 | * @param string $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a boolean a default help is derived)
251 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
252 | */
253 | public function addPhpIniRecommendation($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null)
254 | {
255 | $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, true));
256 | }
257 |
258 | /**
259 | * Adds a requirement collection to the current set of requirements.
260 | *
261 | * @param RequirementCollection $collection A RequirementCollection instance
262 | */
263 | public function addCollection(RequirementCollection $collection)
264 | {
265 | $this->requirements = array_merge($this->requirements, $collection->all());
266 | }
267 |
268 | /**
269 | * Returns both requirements and recommendations.
270 | *
271 | * @return Requirement[]
272 | */
273 | public function all()
274 | {
275 | return $this->requirements;
276 | }
277 |
278 | /**
279 | * Returns all mandatory requirements.
280 | *
281 | * @return Requirement[]
282 | */
283 | public function getRequirements()
284 | {
285 | $array = array();
286 | foreach ($this->requirements as $req) {
287 | if (!$req->isOptional()) {
288 | $array[] = $req;
289 | }
290 | }
291 |
292 | return $array;
293 | }
294 |
295 | /**
296 | * Returns the mandatory requirements that were not met.
297 | *
298 | * @return Requirement[]
299 | */
300 | public function getFailedRequirements()
301 | {
302 | $array = array();
303 | foreach ($this->requirements as $req) {
304 | if (!$req->isFulfilled() && !$req->isOptional()) {
305 | $array[] = $req;
306 | }
307 | }
308 |
309 | return $array;
310 | }
311 |
312 | /**
313 | * Returns all optional recommendations.
314 | *
315 | * @return Requirement[]
316 | */
317 | public function getRecommendations()
318 | {
319 | $array = array();
320 | foreach ($this->requirements as $req) {
321 | if ($req->isOptional()) {
322 | $array[] = $req;
323 | }
324 | }
325 |
326 | return $array;
327 | }
328 |
329 | /**
330 | * Returns the recommendations that were not met.
331 | *
332 | * @return Requirement[]
333 | */
334 | public function getFailedRecommendations()
335 | {
336 | $array = array();
337 | foreach ($this->requirements as $req) {
338 | if (!$req->isFulfilled() && $req->isOptional()) {
339 | $array[] = $req;
340 | }
341 | }
342 |
343 | return $array;
344 | }
345 |
346 | /**
347 | * Returns whether a php.ini configuration is not correct.
348 | *
349 | * @return bool php.ini configuration problem?
350 | */
351 | public function hasPhpIniConfigIssue()
352 | {
353 | foreach ($this->requirements as $req) {
354 | if (!$req->isFulfilled() && $req instanceof PhpIniRequirement) {
355 | return true;
356 | }
357 | }
358 |
359 | return false;
360 | }
361 |
362 | /**
363 | * Returns the PHP configuration file (php.ini) path.
364 | *
365 | * @return string|false php.ini file path
366 | */
367 | public function getPhpIniConfigPath()
368 | {
369 | return get_cfg_var('cfg_file_path');
370 | }
371 | }
372 |
373 | /**
374 | * This class specifies all requirements and optional recommendations that
375 | * are necessary to run the Symfony Standard Edition.
376 | *
377 | * @author Tobias Schultze
378 | * @author Fabien Potencier
379 | */
380 | class SymfonyRequirements extends RequirementCollection
381 | {
382 | const LEGACY_REQUIRED_PHP_VERSION = '5.3.3';
383 | const REQUIRED_PHP_VERSION = '5.5.9';
384 |
385 | /**
386 | * Constructor that initializes the requirements.
387 | */
388 | public function __construct()
389 | {
390 | /* mandatory requirements follow */
391 |
392 | $installedPhpVersion = phpversion();
393 | $requiredPhpVersion = $this->getPhpRequiredVersion();
394 |
395 | $this->addRecommendation(
396 | $requiredPhpVersion,
397 | 'Vendors should be installed in order to check all requirements.',
398 | 'Run the composer install command.',
399 | 'Run the "composer install" command.'
400 | );
401 |
402 | if (false !== $requiredPhpVersion) {
403 | $this->addRequirement(
404 | version_compare($installedPhpVersion, $requiredPhpVersion, '>='),
405 | sprintf('PHP version must be at least %s (%s installed)', $requiredPhpVersion, $installedPhpVersion),
406 | sprintf('You are running PHP version "%s", but Symfony needs at least PHP "%s" to run.
407 | Before using Symfony, upgrade your PHP installation, preferably to the latest version.',
408 | $installedPhpVersion, $requiredPhpVersion),
409 | sprintf('Install PHP %s or newer (installed version is %s)', $requiredPhpVersion, $installedPhpVersion)
410 | );
411 | }
412 |
413 | $this->addRequirement(
414 | version_compare($installedPhpVersion, '5.3.16', '!='),
415 | 'PHP version must not be 5.3.16 as Symfony won\'t work properly with it',
416 | 'Install PHP 5.3.17 or newer (or downgrade to an earlier PHP version)'
417 | );
418 |
419 | $this->addRequirement(
420 | is_dir(__DIR__.'/../vendor/composer'),
421 | 'Vendor libraries must be installed',
422 | 'Vendor libraries are missing. Install composer following instructions from http://getcomposer.org/. '.
423 | 'Then run "php composer.phar install" to install them.'
424 | );
425 |
426 | $cacheDir = is_dir(__DIR__.'/../var/cache') ? __DIR__.'/../var/cache' : __DIR__.'/cache';
427 |
428 | $this->addRequirement(
429 | is_writable($cacheDir),
430 | 'app/cache/ or var/cache/ directory must be writable',
431 | 'Change the permissions of either "app/cache/" or "var/cache/" directory so that the web server can write into it.'
432 | );
433 |
434 | $logsDir = is_dir(__DIR__.'/../var/logs') ? __DIR__.'/../var/logs' : __DIR__.'/logs';
435 |
436 | $this->addRequirement(
437 | is_writable($logsDir),
438 | 'app/logs/ or var/logs/ directory must be writable',
439 | 'Change the permissions of either "app/logs/" or "var/logs/" directory so that the web server can write into it.'
440 | );
441 |
442 | if (version_compare($installedPhpVersion, '7.0.0', '<')) {
443 | $this->addPhpIniRequirement(
444 | 'date.timezone', true, false,
445 | 'date.timezone setting must be set',
446 | 'Set the "date.timezone" setting in php.ini* (like Europe/Paris).'
447 | );
448 | }
449 |
450 | if (false !== $requiredPhpVersion && version_compare($installedPhpVersion, $requiredPhpVersion, '>=')) {
451 | $timezones = array();
452 | foreach (DateTimeZone::listAbbreviations() as $abbreviations) {
453 | foreach ($abbreviations as $abbreviation) {
454 | $timezones[$abbreviation['timezone_id']] = true;
455 | }
456 | }
457 |
458 | $this->addRequirement(
459 | isset($timezones[@date_default_timezone_get()]),
460 | sprintf('Configured default timezone "%s" must be supported by your installation of PHP', @date_default_timezone_get()),
461 | 'Your default timezone is not supported by PHP. Check for typos in your php.ini file and have a look at the list of deprecated timezones at http://php.net/manual/en/timezones.others.php.'
462 | );
463 | }
464 |
465 | $this->addRequirement(
466 | function_exists('iconv'),
467 | 'iconv() must be available',
468 | 'Install and enable the iconv extension.'
469 | );
470 |
471 | $this->addRequirement(
472 | function_exists('json_encode'),
473 | 'json_encode() must be available',
474 | 'Install and enable the JSON extension.'
475 | );
476 |
477 | $this->addRequirement(
478 | function_exists('session_start'),
479 | 'session_start() must be available',
480 | 'Install and enable the session extension.'
481 | );
482 |
483 | $this->addRequirement(
484 | function_exists('ctype_alpha'),
485 | 'ctype_alpha() must be available',
486 | 'Install and enable the ctype extension.'
487 | );
488 |
489 | $this->addRequirement(
490 | function_exists('token_get_all'),
491 | 'token_get_all() must be available',
492 | 'Install and enable the Tokenizer extension.'
493 | );
494 |
495 | $this->addRequirement(
496 | function_exists('simplexml_import_dom'),
497 | 'simplexml_import_dom() must be available',
498 | 'Install and enable the SimpleXML extension.'
499 | );
500 |
501 | if (function_exists('apc_store') && ini_get('apc.enabled')) {
502 | if (version_compare($installedPhpVersion, '5.4.0', '>=')) {
503 | $this->addRequirement(
504 | version_compare(phpversion('apc'), '3.1.13', '>='),
505 | 'APC version must be at least 3.1.13 when using PHP 5.4',
506 | 'Upgrade your APC extension (3.1.13+).'
507 | );
508 | } else {
509 | $this->addRequirement(
510 | version_compare(phpversion('apc'), '3.0.17', '>='),
511 | 'APC version must be at least 3.0.17',
512 | 'Upgrade your APC extension (3.0.17+).'
513 | );
514 | }
515 | }
516 |
517 | $this->addPhpIniRequirement('detect_unicode', false);
518 |
519 | if (extension_loaded('suhosin')) {
520 | $this->addPhpIniRequirement(
521 | 'suhosin.executor.include.whitelist',
522 | create_function('$cfgValue', 'return false !== stripos($cfgValue, "phar");'),
523 | false,
524 | 'suhosin.executor.include.whitelist must be configured correctly in php.ini',
525 | 'Add "phar" to suhosin.executor.include.whitelist in php.ini*.'
526 | );
527 | }
528 |
529 | if (extension_loaded('xdebug')) {
530 | $this->addPhpIniRequirement(
531 | 'xdebug.show_exception_trace', false, true
532 | );
533 |
534 | $this->addPhpIniRequirement(
535 | 'xdebug.scream', false, true
536 | );
537 |
538 | $this->addPhpIniRecommendation(
539 | 'xdebug.max_nesting_level',
540 | create_function('$cfgValue', 'return $cfgValue > 100;'),
541 | true,
542 | 'xdebug.max_nesting_level should be above 100 in php.ini',
543 | 'Set "xdebug.max_nesting_level" to e.g. "250" in php.ini* to stop Xdebug\'s infinite recursion protection erroneously throwing a fatal error in your project.'
544 | );
545 | }
546 |
547 | $pcreVersion = defined('PCRE_VERSION') ? (float) PCRE_VERSION : null;
548 |
549 | $this->addRequirement(
550 | null !== $pcreVersion,
551 | 'PCRE extension must be available',
552 | 'Install the PCRE extension (version 8.0+).'
553 | );
554 |
555 | if (extension_loaded('mbstring')) {
556 | $this->addPhpIniRequirement(
557 | 'mbstring.func_overload',
558 | create_function('$cfgValue', 'return (int) $cfgValue === 0;'),
559 | true,
560 | 'string functions should not be overloaded',
561 | 'Set "mbstring.func_overload" to 0 in php.ini* to disable function overloading by the mbstring extension.'
562 | );
563 | }
564 |
565 | /* optional recommendations follow */
566 |
567 | if (file_exists(__DIR__.'/../vendor/composer')) {
568 | require_once __DIR__.'/../vendor/autoload.php';
569 |
570 | try {
571 | $r = new ReflectionClass('Sensio\Bundle\DistributionBundle\SensioDistributionBundle');
572 |
573 | $contents = file_get_contents(dirname($r->getFileName()).'/Resources/skeleton/app/SymfonyRequirements.php');
574 | } catch (ReflectionException $e) {
575 | $contents = '';
576 | }
577 | $this->addRecommendation(
578 | file_get_contents(__FILE__) === $contents,
579 | 'Requirements file should be up-to-date',
580 | 'Your requirements file is outdated. Run composer install and re-check your configuration.'
581 | );
582 | }
583 |
584 | $this->addRecommendation(
585 | version_compare($installedPhpVersion, '5.3.4', '>='),
586 | 'You should use at least PHP 5.3.4 due to PHP bug #52083 in earlier versions',
587 | 'Your project might malfunction randomly due to PHP bug #52083 ("Notice: Trying to get property of non-object"). Install PHP 5.3.4 or newer.'
588 | );
589 |
590 | $this->addRecommendation(
591 | version_compare($installedPhpVersion, '5.3.8', '>='),
592 | 'When using annotations you should have at least PHP 5.3.8 due to PHP bug #55156',
593 | 'Install PHP 5.3.8 or newer if your project uses annotations.'
594 | );
595 |
596 | $this->addRecommendation(
597 | version_compare($installedPhpVersion, '5.4.0', '!='),
598 | 'You should not use PHP 5.4.0 due to the PHP bug #61453',
599 | 'Your project might not work properly due to the PHP bug #61453 ("Cannot dump definitions which have method calls"). Install PHP 5.4.1 or newer.'
600 | );
601 |
602 | $this->addRecommendation(
603 | version_compare($installedPhpVersion, '5.4.11', '>='),
604 | 'When using the logout handler from the Symfony Security Component, you should have at least PHP 5.4.11 due to PHP bug #63379 (as a workaround, you can also set invalidate_session to false in the security logout handler configuration)',
605 | 'Install PHP 5.4.11 or newer if your project uses the logout handler from the Symfony Security Component.'
606 | );
607 |
608 | $this->addRecommendation(
609 | (version_compare($installedPhpVersion, '5.3.18', '>=') && version_compare($installedPhpVersion, '5.4.0', '<'))
610 | ||
611 | version_compare($installedPhpVersion, '5.4.8', '>='),
612 | 'You should use PHP 5.3.18+ or PHP 5.4.8+ to always get nice error messages for fatal errors in the development environment due to PHP bug #61767/#60909',
613 | 'Install PHP 5.3.18+ or PHP 5.4.8+ if you want nice error messages for all fatal errors in the development environment.'
614 | );
615 |
616 | if (null !== $pcreVersion) {
617 | $this->addRecommendation(
618 | $pcreVersion >= 8.0,
619 | sprintf('PCRE extension should be at least version 8.0 (%s installed)', $pcreVersion),
620 | 'PCRE 8.0+ is preconfigured in PHP since 5.3.2 but you are using an outdated version of it. Symfony probably works anyway but it is recommended to upgrade your PCRE extension.'
621 | );
622 | }
623 |
624 | $this->addRecommendation(
625 | class_exists('DomDocument'),
626 | 'PHP-DOM and PHP-XML modules should be installed',
627 | 'Install and enable the PHP-DOM and the PHP-XML modules.'
628 | );
629 |
630 | $this->addRecommendation(
631 | function_exists('mb_strlen'),
632 | 'mb_strlen() should be available',
633 | 'Install and enable the mbstring extension.'
634 | );
635 |
636 | $this->addRecommendation(
637 | function_exists('iconv'),
638 | 'iconv() should be available',
639 | 'Install and enable the iconv extension.'
640 | );
641 |
642 | $this->addRecommendation(
643 | function_exists('utf8_decode'),
644 | 'utf8_decode() should be available',
645 | 'Install and enable the XML extension.'
646 | );
647 |
648 | $this->addRecommendation(
649 | function_exists('filter_var'),
650 | 'filter_var() should be available',
651 | 'Install and enable the filter extension.'
652 | );
653 |
654 | if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
655 | $this->addRecommendation(
656 | function_exists('posix_isatty'),
657 | 'posix_isatty() should be available',
658 | 'Install and enable the php_posix extension (used to colorize the CLI output).'
659 | );
660 | }
661 |
662 | $this->addRecommendation(
663 | extension_loaded('intl'),
664 | 'intl extension should be available',
665 | 'Install and enable the intl extension (used for validators).'
666 | );
667 |
668 | if (extension_loaded('intl')) {
669 | // in some WAMP server installations, new Collator() returns null
670 | $this->addRecommendation(
671 | null !== new Collator('fr_FR'),
672 | 'intl extension should be correctly configured',
673 | 'The intl extension does not behave properly. This problem is typical on PHP 5.3.X x64 WIN builds.'
674 | );
675 |
676 | // check for compatible ICU versions (only done when you have the intl extension)
677 | if (defined('INTL_ICU_VERSION')) {
678 | $version = INTL_ICU_VERSION;
679 | } else {
680 | $reflector = new ReflectionExtension('intl');
681 |
682 | ob_start();
683 | $reflector->info();
684 | $output = strip_tags(ob_get_clean());
685 |
686 | preg_match('/^ICU version +(?:=> )?(.*)$/m', $output, $matches);
687 | $version = $matches[1];
688 | }
689 |
690 | $this->addRecommendation(
691 | version_compare($version, '4.0', '>='),
692 | 'intl ICU version should be at least 4+',
693 | 'Upgrade your intl extension with a newer ICU version (4+).'
694 | );
695 |
696 | if (class_exists('Symfony\Component\Intl\Intl')) {
697 | $this->addRecommendation(
698 | \Symfony\Component\Intl\Intl::getIcuDataVersion() <= \Symfony\Component\Intl\Intl::getIcuVersion(),
699 | sprintf('intl ICU version installed on your system is outdated (%s) and does not match the ICU data bundled with Symfony (%s)', \Symfony\Component\Intl\Intl::getIcuVersion(), \Symfony\Component\Intl\Intl::getIcuDataVersion()),
700 | 'To get the latest internationalization data upgrade the ICU system package and the intl PHP extension.'
701 | );
702 | if (\Symfony\Component\Intl\Intl::getIcuDataVersion() <= \Symfony\Component\Intl\Intl::getIcuVersion()) {
703 | $this->addRecommendation(
704 | \Symfony\Component\Intl\Intl::getIcuDataVersion() === \Symfony\Component\Intl\Intl::getIcuVersion(),
705 | sprintf('intl ICU version installed on your system (%s) does not match the ICU data bundled with Symfony (%s)', \Symfony\Component\Intl\Intl::getIcuVersion(), \Symfony\Component\Intl\Intl::getIcuDataVersion()),
706 | 'To avoid internationalization data inconsistencies upgrade the symfony/intl component.'
707 | );
708 | }
709 | }
710 |
711 | $this->addPhpIniRecommendation(
712 | 'intl.error_level',
713 | create_function('$cfgValue', 'return (int) $cfgValue === 0;'),
714 | true,
715 | 'intl.error_level should be 0 in php.ini',
716 | 'Set "intl.error_level" to "0" in php.ini* to inhibit the messages when an error occurs in ICU functions.'
717 | );
718 | }
719 |
720 | $accelerator =
721 | (extension_loaded('eaccelerator') && ini_get('eaccelerator.enable'))
722 | ||
723 | (extension_loaded('apc') && ini_get('apc.enabled'))
724 | ||
725 | (extension_loaded('Zend Optimizer+') && ini_get('zend_optimizerplus.enable'))
726 | ||
727 | (extension_loaded('Zend OPcache') && ini_get('opcache.enable'))
728 | ||
729 | (extension_loaded('xcache') && ini_get('xcache.cacher'))
730 | ||
731 | (extension_loaded('wincache') && ini_get('wincache.ocenabled'))
732 | ;
733 |
734 | $this->addRecommendation(
735 | $accelerator,
736 | 'a PHP accelerator should be installed',
737 | 'Install and/or enable a PHP accelerator (highly recommended).'
738 | );
739 |
740 | if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
741 | $this->addRecommendation(
742 | $this->getRealpathCacheSize() >= 5 * 1024 * 1024,
743 | 'realpath_cache_size should be at least 5M in php.ini',
744 | 'Setting "realpath_cache_size" to e.g. "5242880" or "5M" in php.ini* may improve performance on Windows significantly in some cases.'
745 | );
746 | }
747 |
748 | $this->addPhpIniRecommendation('short_open_tag', false);
749 |
750 | $this->addPhpIniRecommendation('magic_quotes_gpc', false, true);
751 |
752 | $this->addPhpIniRecommendation('register_globals', false, true);
753 |
754 | $this->addPhpIniRecommendation('session.auto_start', false);
755 |
756 | $this->addRecommendation(
757 | class_exists('PDO'),
758 | 'PDO should be installed',
759 | 'Install PDO (mandatory for Doctrine).'
760 | );
761 |
762 | if (class_exists('PDO')) {
763 | $drivers = PDO::getAvailableDrivers();
764 | $this->addRecommendation(
765 | count($drivers) > 0,
766 | sprintf('PDO should have some drivers installed (currently available: %s)', count($drivers) ? implode(', ', $drivers) : 'none'),
767 | 'Install PDO drivers (mandatory for Doctrine).'
768 | );
769 | }
770 | }
771 |
772 | /**
773 | * Loads realpath_cache_size from php.ini and converts it to int.
774 | *
775 | * (e.g. 16k is converted to 16384 int)
776 | *
777 | * @return int
778 | */
779 | protected function getRealpathCacheSize()
780 | {
781 | $size = ini_get('realpath_cache_size');
782 | $size = trim($size);
783 | $unit = strtolower(substr($size, -1, 1));
784 | switch ($unit) {
785 | case 'g':
786 | return $size * 1024 * 1024 * 1024;
787 | case 'm':
788 | return $size * 1024 * 1024;
789 | case 'k':
790 | return $size * 1024;
791 | default:
792 | return (int) $size;
793 | }
794 | }
795 |
796 | /**
797 | * Defines PHP required version from Symfony version.
798 | *
799 | * @return string|false The PHP required version or false if it could not be guessed
800 | */
801 | protected function getPhpRequiredVersion()
802 | {
803 | if (!file_exists($path = __DIR__.'/../composer.lock')) {
804 | return false;
805 | }
806 |
807 | $composerLock = json_decode(file_get_contents($path), true);
808 | foreach ($composerLock['packages'] as $package) {
809 | $name = $package['name'];
810 | if ('symfony/symfony' !== $name && 'symfony/http-kernel' !== $name) {
811 | continue;
812 | }
813 |
814 | return (int) $package['version'][1] > 2 ? self::REQUIRED_PHP_VERSION : self::LEGACY_REQUIRED_PHP_VERSION;
815 | }
816 |
817 | return false;
818 | }
819 | }
820 |
--------------------------------------------------------------------------------
/var/cache/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veloxy/purl/4ce902ba7197e0a9206df140173bb492366fce1f/var/cache/.gitkeep
--------------------------------------------------------------------------------
/var/logs/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veloxy/purl/4ce902ba7197e0a9206df140173bb492366fce1f/var/logs/.gitkeep
--------------------------------------------------------------------------------
/var/sessions/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veloxy/purl/4ce902ba7197e0a9206df140173bb492366fce1f/var/sessions/.gitkeep
--------------------------------------------------------------------------------
/web/.htaccess:
--------------------------------------------------------------------------------
1 | # Use the front controller as index file. It serves as a fallback solution when
2 | # every other rewrite/redirect fails (e.g. in an aliased environment without
3 | # mod_rewrite). Additionally, this reduces the matching process for the
4 | # start page (path "/") because otherwise Apache will apply the rewriting rules
5 | # to each configured DirectoryIndex file (e.g. index.php, index.html, index.pl).
6 | DirectoryIndex app.php
7 |
8 | # By default, Apache does not evaluate symbolic links if you did not enable this
9 | # feature in your server configuration. Uncomment the following line if you
10 | # install assets as symlinks or if you experience problems related to symlinks
11 | # when compiling LESS/Sass/CoffeScript assets.
12 | # Options FollowSymlinks
13 |
14 | # Disabling MultiViews prevents unwanted negotiation, e.g. "/app" should not resolve
15 | # to the front controller "/app.php" but be rewritten to "/app.php/app".
16 |
17 | Options -MultiViews
18 |
19 |
20 |
21 | RewriteEngine On
22 |
23 | # Determine the RewriteBase automatically and set it as environment variable.
24 | # If you are using Apache aliases to do mass virtual hosting or installed the
25 | # project in a subdirectory, the base path will be prepended to allow proper
26 | # resolution of the app.php file and to redirect to the correct URI. It will
27 | # work in environments without path prefix as well, providing a safe, one-size
28 | # fits all solution. But as you do not need it in this case, you can comment
29 | # the following 2 lines to eliminate the overhead.
30 | RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
31 | RewriteRule ^(.*) - [E=BASE:%1]
32 |
33 | # Sets the HTTP_AUTHORIZATION header removed by Apache
34 | RewriteCond %{HTTP:Authorization} .
35 | RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
36 |
37 | # Redirect to URI without front controller to prevent duplicate content
38 | # (with and without `/app.php`). Only do this redirect on the initial
39 | # rewrite by Apache and not on subsequent cycles. Otherwise we would get an
40 | # endless redirect loop (request -> rewrite to front controller ->
41 | # redirect -> request -> ...).
42 | # So in case you get a "too many redirects" error or you always get redirected
43 | # to the start page because your Apache does not expose the REDIRECT_STATUS
44 | # environment variable, you have 2 choices:
45 | # - disable this feature by commenting the following 2 lines or
46 | # - use Apache >= 2.3.9 and replace all L flags by END flags and remove the
47 | # following RewriteCond (best solution)
48 | RewriteCond %{ENV:REDIRECT_STATUS} ^$
49 | RewriteRule ^app\.php(?:/(.*)|$) %{ENV:BASE}/$1 [R=301,L]
50 |
51 | # If the requested filename exists, simply serve it.
52 | # We only want to let Apache serve files and not directories.
53 | RewriteCond %{REQUEST_FILENAME} -f
54 | RewriteRule ^ - [L]
55 |
56 | # Rewrite all other queries to the front controller.
57 | RewriteRule ^ %{ENV:BASE}/app.php [L]
58 |
59 |
60 |
61 |
62 | # When mod_rewrite is not available, we instruct a temporary redirect of
63 | # the start page to the front controller explicitly so that the website
64 | # and the generated links can still be used.
65 | RedirectMatch 302 ^/$ /app.php/
66 | # RedirectTemp cannot be used instead
67 |
68 |
69 |
--------------------------------------------------------------------------------
/web/app.php:
--------------------------------------------------------------------------------
1 | unregister();
18 | $apcLoader->register(true);
19 | */
20 |
21 | $kernel = new AppKernel('prod', false);
22 | $kernel->loadClassCache();
23 | //$kernel = new AppCache($kernel);
24 |
25 | // When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter
26 | //Request::enableHttpMethodParameterOverride();
27 | $request = Request::createFromGlobals();
28 | $response = $kernel->handle($request);
29 | $response->send();
30 | $kernel->terminate($request, $response);
31 |
--------------------------------------------------------------------------------
/web/app_dev.php:
--------------------------------------------------------------------------------
1 | loadClassCache();
14 | $request = Request::createFromGlobals();
15 | $response = $kernel->handle($request);
16 | $response->send();
17 | $kernel->terminate($request, $response);
18 |
--------------------------------------------------------------------------------
/web/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/veloxy/purl/4ce902ba7197e0a9206df140173bb492366fce1f/web/apple-touch-icon.png
--------------------------------------------------------------------------------
/web/config.php:
--------------------------------------------------------------------------------
1 | getFailedRequirements();
30 | $minorProblems = $symfonyRequirements->getFailedRecommendations();
31 | $hasMajorProblems = (bool) count($majorProblems);
32 | $hasMinorProblems = (bool) count($minorProblems);
33 |
34 | ?>
35 |
36 |
37 |
38 |
39 |
40 | Symfony Configuration Checker
41 |
42 |
43 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
Configuration Checker
158 |
159 | This script analyzes your system to check whether is
160 | ready to run Symfony applications.
161 |
162 |
163 |
164 |
Major problems
165 |
Major problems have been detected and must be fixed before continuing:
166 |
167 |
168 |
getTestMessage() ?>
169 |
getHelpHtml() ?>
170 |
171 |
172 |
173 |
174 |
175 |
176 |
Recommendations
177 |
178 | Additionally, toTo enhance your Symfony experience,
179 | it’s recommended that you fix the following:
180 |
*
192 | getPhpIniConfigPath()): ?>
193 | Changes to the php.ini file must be done in "getPhpIniConfigPath() ?>".
194 |
195 | To change settings, create a "php.ini".
196 |
197 |
198 |
199 |
200 |
201 |
All checks passed successfully. Your system is ready to run Symfony applications.