comparison vendor/psy/psysh/src/ExecutionLoop/RunkitReloader.php @ 13:5fb285c0d0e3

Update Drupal core to 8.4.7 via Composer. Security update; I *think* we've been lucky to get away with this so far, as we don't support self-registration which seems to be used by the so-called "drupalgeddon 2" attack that 8.4.5 was vulnerable to.
author Chris Cannam
date Mon, 23 Apr 2018 09:33:26 +0100
parents
children 129ea1e6d783
comparison
equal deleted inserted replaced
12:7a779792577d 13:5fb285c0d0e3
1 <?php
2
3 /*
4 * This file is part of Psy Shell.
5 *
6 * (c) 2012-2018 Justin Hileman
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 namespace Psy\ExecutionLoop;
13
14 use Psy\Exception\ParseErrorException;
15 use Psy\ParserFactory;
16 use Psy\Shell;
17
18 /**
19 * A runkit-based code reloader, which is pretty much magic.
20 */
21 class RunkitReloader extends AbstractListener
22 {
23 private $parser;
24 private $timestamps = [];
25
26 /**
27 * Only enabled if Runkit is installed.
28 *
29 * @return bool
30 */
31 public static function isSupported()
32 {
33 return extension_loaded('runkit');
34 }
35
36 /**
37 * Construct a Runkit Reloader.
38 *
39 * @todo Pass in Parser Factory instance for dependency injection?
40 */
41 public function __construct()
42 {
43 $parserFactory = new ParserFactory();
44 $this->parser = $parserFactory->createParser();
45 }
46
47 /**
48 * Reload code on input.
49 *
50 * @param Shell $shell
51 * @param string $input
52 */
53 public function onInput(Shell $shell, $input)
54 {
55 $this->reload($shell);
56 }
57
58 /**
59 * Look through included files and update anything with a new timestamp.
60 *
61 * @param Shell $shell
62 */
63 private function reload(Shell $shell)
64 {
65 clearstatcache();
66 $modified = [];
67
68 foreach (get_included_files() as $file) {
69 $timestamp = filemtime($file);
70
71 if (!isset($this->timestamps[$file])) {
72 $this->timestamps[$file] = $timestamp;
73 continue;
74 }
75
76 if ($this->timestamps[$file] === $timestamp) {
77 continue;
78 }
79
80 if (!$this->lintFile($file)) {
81 $msg = sprintf('Modified file "%s" could not be reloaded', $file);
82 $shell->writeException(new ParseErrorException($msg));
83 continue;
84 }
85
86 $modified[] = $file;
87 $this->timestamps[$file] = $timestamp;
88 }
89
90 // switch (count($modified)) {
91 // case 0:
92 // return;
93
94 // case 1:
95 // printf("Reloading modified file: \"%s\"\n", str_replace(getcwd(), '.', $file));
96 // break;
97
98 // default:
99 // printf("Reloading %d modified files\n", count($modified));
100 // break;
101 // }
102
103 foreach ($modified as $file) {
104 runkit_import($file, (
105 RUNKIT_IMPORT_FUNCTIONS |
106 RUNKIT_IMPORT_CLASSES |
107 RUNKIT_IMPORT_CLASS_METHODS |
108 RUNKIT_IMPORT_CLASS_CONSTS |
109 RUNKIT_IMPORT_CLASS_PROPS |
110 RUNKIT_IMPORT_OVERRIDE
111 ));
112 }
113 }
114
115 /**
116 * Should this file be re-imported?
117 *
118 * Use PHP-Parser to ensure that the file is valid PHP.
119 *
120 * @param string $file
121 *
122 * @return bool
123 */
124 private function lintFile($file)
125 {
126 // first try to parse it
127 try {
128 $this->parser->parse(file_get_contents($file));
129 } catch (\Exception $e) {
130 return false;
131 }
132
133 return true;
134 }
135 }