44cc2c0e507c9a922f6e61dce669948c8f84c07a
[yaffs-website] / vendor / psy / psysh / src / Command / SudoCommand.php
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\Command;
13
14 use PhpParser\NodeTraverser;
15 use PhpParser\PrettyPrinter\Standard as Printer;
16 use Psy\Input\CodeArgument;
17 use Psy\ParserFactory;
18 use Psy\Readline\Readline;
19 use Psy\Sudo\SudoVisitor;
20 use Symfony\Component\Console\Input\InputInterface;
21 use Symfony\Component\Console\Output\OutputInterface;
22
23 /**
24  * Evaluate PHP code, bypassing visibility restrictions.
25  */
26 class SudoCommand extends Command
27 {
28     private $readline;
29     private $parser;
30     private $traverser;
31     private $printer;
32
33     /**
34      * {@inheritdoc}
35      */
36     public function __construct($name = null)
37     {
38         $parserFactory = new ParserFactory();
39         $this->parser = $parserFactory->createParser();
40
41         $this->traverser = new NodeTraverser();
42         $this->traverser->addVisitor(new SudoVisitor());
43
44         $this->printer = new Printer();
45
46         parent::__construct($name);
47     }
48
49     /**
50      * Set the Shell's Readline service.
51      *
52      * @param Readline $readline
53      */
54     public function setReadline(Readline $readline)
55     {
56         $this->readline = $readline;
57     }
58
59     /**
60      * {@inheritdoc}
61      */
62     protected function configure()
63     {
64         $this
65             ->setName('sudo')
66             ->setDefinition([
67                 new CodeArgument('code', CodeArgument::REQUIRED, 'Code to execute.'),
68             ])
69             ->setDescription('Evaluate PHP code, bypassing visibility restrictions.')
70             ->setHelp(
71                 <<<'HELP'
72 Evaluate PHP code, bypassing visibility restrictions.
73
74 e.g.
75 <return>>>> $sekret->whisper("hi")</return>
76 <return>PHP error:  Call to private method Sekret::whisper() from context '' on line 1</return>
77
78 <return>>>> sudo $sekret->whisper("hi")</return>
79 <return>=> "hi"</return>
80
81 <return>>>> $sekret->word</return>
82 <return>PHP error:  Cannot access private property Sekret::$word on line 1</return>
83
84 <return>>>> sudo $sekret->word</return>
85 <return>=> "hi"</return>
86
87 <return>>>> $sekret->word = "please"</return>
88 <return>PHP error:  Cannot access private property Sekret::$word on line 1</return>
89
90 <return>>>> sudo $sekret->word = "please"</return>
91 <return>=> "please"</return>
92 HELP
93             );
94     }
95
96     /**
97      * {@inheritdoc}
98      */
99     protected function execute(InputInterface $input, OutputInterface $output)
100     {
101         $code = $input->getArgument('code');
102
103         // special case for !!
104         if ($code === '!!') {
105             $history = $this->readline->listHistory();
106             if (count($history) < 2) {
107                 throw new \InvalidArgumentException('No previous command to replay');
108             }
109             $code = $history[count($history) - 2];
110         }
111
112         if (strpos('<?', $code) === false) {
113             $code = '<?php ' . $code;
114         }
115
116         $nodes = $this->traverser->traverse($this->parse($code));
117
118         $sudoCode = $this->printer->prettyPrint($nodes);
119         $shell = $this->getApplication();
120         $shell->addCode($sudoCode, !$shell->hasCode());
121     }
122
123     /**
124      * Lex and parse a string of code into statements.
125      *
126      * @param string $code
127      *
128      * @return array Statements
129      */
130     private function parse($code)
131     {
132         try {
133             return $this->parser->parse($code);
134         } catch (\PhpParser\Error $e) {
135             if (strpos($e->getMessage(), 'unexpected EOF') === false) {
136                 throw $e;
137             }
138
139             // If we got an unexpected EOF, let's try it again with a semicolon.
140             return $this->parser->parse($code . ';');
141         }
142     }
143 }